以下是详细的讲解:
C++数据结构之哈希表的实现
哈希表的概念
哈希表是一种能够实现快速查找的散列表,通过将关键字映射到哈希表中的一个位置来实现快速查找。哈希表的查询、删除时间复杂度为O(1),操作效率非常高,所以常常被用来对大量数据进行检索。
哈希表的实现
哈希函数
哈希函数的主要作用就是将任意长度的输入数据转化为固定长度的散列值,一般采用对关键字进行取模的方式,也可以使用其他算法。哈希函数的设计对哈希表的性能有着至关重要的作用。
例如,下面是一个简单的哈希函数实现:
int hashFunc(int key, int tableSize){
return key % tableSize;
}
其中,key
是关键字,tableSize
是哈希表的大小,hashFunc
函数将key
值取模作为哈希值返回。
冲突解决
当不同的关键字映射到同一个哈希值时,就发生了冲突。哈希表的冲突解决方法有很多种,这里介绍两种比较常用的方法。
链表法
链表法是一种将冲突的关键字以链表的形式串联起来,存放到同一个哈希值对应的位置上。
例如,以下是一个简单的链表法哈希表实现:
struct Node{
int key;
Node* next;
Node(int k) : key(k), next(nullptr) {}
};
class HashTable{
private:
int tableSize;
vector<Node*> hashTable;
int hashFunc(int key){
return key % tableSize;
}
public:
HashTable(int size){
tableSize = size;
hashTable.resize(tableSize);
}
void insert(int key){
int hashValue = hashFunc(key);
if(hashTable[hashValue] == nullptr){
hashTable[hashValue] = new Node(key);
} else {
Node* currentNode = hashTable[hashValue];
while(currentNode->next != nullptr){
currentNode = currentNode->next;
}
currentNode->next = new Node(key);
}
}
bool search(int key){
int hashValue = hashFunc(key);
Node* currentNode = hashTable[hashValue];
while(currentNode != nullptr){
if(currentNode->key == key){
return true;
}
currentNode = currentNode->next;
}
return false;
}
void remove(int key){
int hashValue = hashFunc(key);
Node* currentNode = hashTable[hashValue];
Node* prevNode = nullptr;
while(currentNode != nullptr){
if(currentNode->key == key){
if(prevNode == nullptr){
hashTable[hashValue] = currentNode->next;
} else {
prevNode->next = currentNode->next;
}
delete currentNode;
return;
}
prevNode = currentNode;
currentNode = currentNode->next;
}
return;
}
};
在上面的实现中,我们将哈希值相同的关键字以链表的形式进行存储,这样,在查找关键字的时候,如果哈希值相同,我们就沿着链表依次查找,直到找到目标位置或者链表遍历完毕。
开放定址法
开放定址法是一种将冲突的关键字插入到哈希表中空闲的地址上,常见的几种方式有线性探测、二次探测和双重散列等。
例如,以下是一个简单的线性探测哈希表实现:
class HashTable{
private:
int tableSize;
vector<int> hashTable;
int hashFunc(int key){
return key % tableSize;
}
public:
HashTable(int size){
tableSize = size;
hashTable.resize(tableSize, -1);
}
void insert(int key){
int hashValue = hashFunc(key);
int i = 0;
while(hashTable[(hashValue + i) % tableSize] != -1){
i++;
}
hashTable[(hashValue + i) % tableSize] = key;
}
bool search(int key){
int hashValue = hashFunc(key);
int i = 0;
while(hashTable[(hashValue + i) % tableSize] != key && hashTable[(hashValue + i) % tableSize] != -1){
i++;
}
if(hashTable[(hashValue + i) % tableSize] == key){
return true;
} else {
return false;
}
}
void remove(int key){
int hashValue = hashFunc(key);
int i = 0;
while(hashTable[(hashValue + i) % tableSize] != key && hashTable[(hashValue + i) % tableSize] != -1){
i++;
}
if(hashTable[(hashValue + i) % tableSize] == key){
hashTable[(hashValue + i) % tableSize] = -1;
}
return;
}
};
在上面的实现中,我们使用线性探测的方式解决了冲突问题,具体来说,在插入关键字的时候,如果目标位置已经有了其他关键字,我们就把目标位置后继的位置再判断一遍,直到找到一个空闲的地址,然后将关键字插入到该位置。在查找和删除时,我们同样需要进行连续的查找操作直到查找到目标位置或者发现该位置已经被占用了。
示例说明
链表法哈希表
以下是一个简单的用链表法实现的哈希表示例:
HashTable hashTable(10);
hashTable.insert(1);
hashTable.insert(12);
hashTable.insert(23);
hashTable.insert(14);
hashTable.insert(35);
cout << hashTable.search(12) << endl;
cout << hashTable.search(18) << endl;
hashTable.remove(14);
cout << hashTable.search(14) << endl;
运行结果如下:
1
0
0
在上面的示例中,我们首先创建了一个哈希表,然后插入了5个不同的关键字。然后我们分别查找哈希表中是否包含12和18这两个关键字,最后删除14这个关键字,然后再次检查哈希表中是否包含14这个关键字。可以看到,我们使用链表法实现的哈希表能够正常地进行插入、查找、删除操作,并且在删除关键字后,能够正确地返回“false”。
开放定址法哈希表
以下是一个简单的用开放定址法实现的哈希表示例:
HashTable hashTable(10);
hashTable.insert(1);
hashTable.insert(12);
hashTable.insert(23);
hashTable.insert(14);
hashTable.insert(35);
cout << hashTable.search(12) << endl;
cout << hashTable.search(18) << endl;
hashTable.remove(14);
cout << hashTable.search(14) << endl;
运行结果如下:
1
0
0
在上面的示例中,我们同样首先创建了一个哈希表,然后插入了5个不同的关键字。然后我们同样分别查找哈希表中是否包含12和18这两个关键字,最后删除14这个关键字,然后再次检查哈希表中是否包含14这个关键字。可以看到,我们使用开放定址法实现的哈希表同样能够正常地进行插入、查找、删除操作,并且在删除关键字后,能够正确地返回“false”。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++数据结构之哈希表的实现 - Python技术站