HashTable是以常数时间进行进行插入,删除和查找的数据结构。其查找原理是:通过哈希函数Hash(),进行哈希得到value,value为哈希表的下表。怎么能得到均衡的value呢?
Hash()(哈希一般是通过字符串映射到键值)
Index HashTable::Hash_one(const ElemType& key, const size_t tablesize)const {
size_t hashval = 0;
int i = 0;
while (key[i] != '\0') {
hashval += key[i];
++i;
}
return hashval % tablesize;
}
Index HashTable::Hash_two(const ElemType& key, const size_t tablesize)const {
auto hashval = key[0] + 27 * key[1] + 27 * 27 * key[2];
return hashval % tablesize;
}
Index HashTable::Hash_three(const ElemType& key, const size_t tablesize)const {
size_t hashval = 0;
int i = 0;
while (key[i] != '\0') {
hashval = (hashval<<5) + key[i];
++i;
}
return hashval % tablesize;
}
经过测试只有Hash_Three()得到的键值是均衡分布的。
但有时候不同的字符串会映射到相同的键值,怎么解决这个问题呢?(我们也叫发生冲突)
方法一:分离链接法(数组和链表的组合实现)
全部源码如下:
#include<iostream>
#include<memory>
#include<vector>
typedef size_t Index;
typedef std::string ElemType;
typedef struct Listnode* List;
typedef struct Listnode* Position;
const size_t MaxSize = 11;
struct Listnode {
ElemType element;
List next;
};
struct HashTab {
size_t tablesize;
List* lists;
};
class HashTable {
public:
HashTable() :hashtable(std::make_unique<HashTab>()) {
hashtable->tablesize = MaxSize;
hashtable->lists = new List[MaxSize]();
}
~HashTable() {
if (hashtable->lists)
delete[] hashtable->lists;
}
public:
Index Hash_one(const ElemType& key, const size_t tablesize)const;
Index Hash_two(const ElemType& key, const size_t tablesize)const;
Index Hash_three(const ElemType& key, const size_t tablesize)const;
public:
Position Find(const ElemType key)const;
void Insert(const ElemType key);
void Delete(const ElemType key);
void Display()const;
private:
std::unique_ptr<HashTab>hashtable;
};
Index HashTable::Hash_one(const ElemType& key, const size_t tablesize)const {
size_t hashval = 0;
int i = 0;
while (key[i] != '\0') {
hashval += key[i];
++i;
}
return hashval % tablesize;
}
Index HashTable::Hash_two(const ElemType& key, const size_t tablesize)const {
auto hashval = key[0] + 27 * key[1] + 27 * 27 * key[2];
return hashval % tablesize;
}
Index HashTable::Hash_three(const ElemType& key, const size_t tablesize)const {
size_t hashval = 0;
int i = 0;
while (key[i] != '\0') {
hashval = (hashval << 5) + key[i];
++i;
}
return hashval % tablesize;
}
Position HashTable::Find(const ElemType key)const {
auto p = hashtable->lists[Hash_three(key, hashtable->tablesize)];
if (p != nullptr) {
while (p != nullptr) {
if (p->element == key)
return p;
p = p->next;
}
}
return nullptr;
}
void HashTable::Insert(const ElemType key) {
if (auto pos = Find(key))
return;
else {
auto index = Hash_three(key,hashtable->tablesize);
if (hashtable->lists[index] == nullptr) {
hashtable->lists[index] = new Listnode;
auto newnode = new Listnode;
newnode->element = key;
hashtable->lists[index] = newnode;
newnode->next = nullptr;
}
else {
auto newnode = new Listnode;
newnode->element = key;
auto L = hashtable->lists[index];
newnode->next = L->next;
L->next = newnode;
}
}
}
void HashTable::Delete(const ElemType key) { /*Lazy Delete*/
if (auto p = Find(key)) {
auto index = Hash_three(key, hashtable->tablesize);
auto l = hashtable->lists[index];
if (l->next == nullptr)
l->element = "";
else {
while (true) {
if (l== p)
break;
l = l->next;
}
l->element = "";
}
}
else
return;
}
void HashTable::Display()const {
for (int i = 0; i < hashtable->tablesize; ++i) {
if (auto p = hashtable->lists[i]) {
while (p != nullptr ) {
std::cout << "i: " << i << " " << p->element.c_str() << std::endl;
p = p->next;
}
}
}
}
int main(void)
{
HashTable hash;
const std::string name_one = "Jay";
const std::string name_two = "Cry";
const std::string name_three = "Cherry";
const std::string name_four = "Yun";
const std::string name_five = "Jerry";
const std::string name_six = "Derty";
const std::string name_seven = "Striy";
const std::string name_eight = "Actry";
hash.Insert(name_one);
hash.Insert(name_two);
hash.Insert(name_three);
hash.Insert(name_four);
hash.Insert(name_five);
hash.Insert(name_six);
hash.Insert(name_seven);
hash.Insert(name_eight);
hash.Display();
std::cout << std::endl;
std::cout << "Delete two elems:Detry Yun" << std::endl;
hash.Delete(name_six);
hash.Delete(name_four);
hash.Display();
return 0;
}
我们定义装填因子()为哈希表中元素个数与哈希表的大小 。
越接近1说明哈希越好。分离链接法使得
接近1。