实现哈希表时,我们常见的方法是线性探测、二次探测,这两个算法也很简单。若有兴趣,可以查看我的博客。但是,这两个算法有一个共同点就是:空间利用率低。为什么这么说呢?线性探测、二次探测的高效性很大程度上要取决于它的载荷因子,载荷因子即:存放关键字个数/空间大小。
通过查阅资料,我发现,使用素数做除数可以减少哈希冲突(具体原因不详,大师专研的,发现很好用,就在这里分享给大家)。见下:
----素数表
// 使用素数表对齐做哈希表的容量,降低哈希冲突
const int _PrimeSize = 28;
static const unsigned long _PrimeList [_PrimeSize] =
{
53ul,97ul,193ul,389ul,769ul,
1543ul,3079ul,6151ul,12289ul,24593ul,128);font-size:16px;">49157ul,98317ul,196613ul,393241ul,786433ul,128);font-size:16px;">1572869ul,3145739ul,6291469ul,12582917ul,25165843ul,128);font-size:16px;">50331653ul,100663319ul,201326611ul,402653189ul,805306457ul,128);font-size:16px;">1610612741ul,3221225473ul,4294967291ul
};
开链法(哈希桶)结构:
而哈希桶实现时,我们可以将载荷因子设成1.
代码如下:
#define_CRT_SECURE_NO_WARNINGS1 #include<iostream> usingnamespacestd; #include<vector> template<classK,classV> structHashTableNode { K_key; V_value; HashTableNode*_next; HashTableNode(constK&key,constV&value) :_key(key),_value(value),_next(NULL) {} }; template<classK,classV> classHashTable { public: typedefHashTableNode<K,V>Node; HashTable() :_table(NULL),_size() {} size_t_HashFunc(constK&key) { //_table.size()表示哈希桶的空间大小 returnkey%_table.size(); } //拷贝构造 HashTable(constHashTable&ht) { //将哈希表ht拷贝给this this->_table.resize(ht._table.size()); for(inti=0;i<ht._table.size();i++) { Node*cur=ht._table[i]; while(cur) { Node*tmp=newNode(cur->_key,cur->_value); tmp->_next=_table[i]; _table[i]=tmp; this->_size++; cur=cur->_next; } } } HashTable<K,V>operator=(constHashTable<K,V>&ht) { if(&ht!=this) { //删除哈希表this for(inti=0;i<this->_table.size();i++) { Node*cur=_table[i]; while(cur) { Node*del=cur; cur=cur->_next; /*deletedel; del=NULL;*/ Remove(del->_key); } } //将哈希表ht拷贝给this this->_table.resize(ht._table.size()); for(inti=0;i<ht._table.size();i++) { Node*cur=ht._table[i]; while(cur) { Node*tmp=newNode(cur->_key,cur->_value); tmp->_next=_table[i]; _table[i]=tmp; this->_size++; cur=cur->_next; } } } return*this; } //赋值运算符重载的现代写法 HashTable<K,V>operator=(HashTable<K,V>ht) { if(&ht!=this) { swap(_table,ht._table); swap(_size,ht._size); } return*this; } ~HashTable() { //删除哈希表ht if(this->_table.size()!=0) { for(inti=0;i<this->_table.size();i++) { Node*cur=_table[i]; while(cur) { Node*del=cur; cur=cur->_next; deletedel; del=NULL; } } } } //获取新的哈希表容量大小 size_t_GetnewSize() { staticconstint_PrimeSize=28; staticconstunsignedlong_PrimeList[_PrimeSize]= { 53ul,1543ul,49157ul,1572869ul,50331653ul,1610612741ul,4294967291ul }; for(inti=0;i<_PrimeSize;i++) { if(_PrimeList[i]>_table.size()) { return_PrimeList[i]; } } return_PrimeList[_PrimeSize-1]; } //给哈希桶扩容 void_ExpandCapacity() { //开辟新的更大容量的哈希表 size_tnewSize=_GetnewSize(); vector<Node*>newTable; newTable.resize(newSize); //将每处顺序表上的单链表元素摘下来插入到新的顺序表上 for(inti=0;i<_table.size();i++) { Node*cur=_table[i]; while(cur) { Node*tmp=cur; cur=cur->_next; intindex=_HashFunc(tmp->_key); //头插法插插节点 tmp->_next=newTable[index]; newTable[index]=tmp; } _table[i]=NULL; } _table.swap(newTable); } //插入关键字 boolInsert(constK&key,constV&value) { //检查载荷因子,考虑是否扩容 //哈希桶的载荷因子设置为1 if(_size==_table.size()) { _ExpandCapacity(); } //往顺序表的index处插入节点 size_tindex=_HashFunc(key); Node*begin=_table[index]; while(begin) { //设计成不可出现重复元素 if(begin->_key==key) { returnfalse; } begin=begin->_next; } //考虑到同一条单链表上,无所谓元素存放顺序,且较尾插简单。--》头插 Node*tmp=newNode(key,value); tmp->_next=_table[index]; _table[index]=tmp; _size++; returntrue; } //查找关键字 Node*Find(constK&key) { intindex=_HashFunc(key); Node*cur=_table[index]; while(cur) { if(cur->_key==key) returncur; cur=cur->_next; } returnNULL; } //删除关键字 boolRemove(constK&key) { intindex=_HashFunc(key); Node*cur=_table[index]; Node*prev=NULL; while(cur) { if(cur->_key==key) break; prev=cur; cur=cur->_next; } if(cur) { if(cur==_table[index]) { _table[index]=cur->_next; } else { Node*next=cur->_next; prev->_next=next; } deletecur; cur=NULL; --_size; returntrue; } returnfalse; } //打印哈希桶 voidPrintHashTable() { for(inti=0;i<_table.size();i++) { Node*cur=_table[i]; cout<<i<<":"; while(cur) { cout<<cur->_key<<"->"; cur=cur->_next; } cout<<"NULL"<<endl; } cout<<endl; } private: vector<Node*>_table; size_t_size;//数据个数 }; voidTestHashTableBucket() { typedefHashTableNode<int,char>Node; HashTable<int,char>ht; ht.Insert(1,'a'); ht.Insert(2,'b'); ht.Insert(3,'c'); ht.Insert(4,'d'); ht.Insert(5,'d'); ht.Insert(54,'x'); ht.Insert(55,'y'); ht.Insert(56,'z'); ht.PrintHashTable(); /*Node*ret=ht.Find(5); cout<<ret->_value<<endl; ht.Remove(1); ht.Remove(6); ht.PrintHashTable();*/ /*HashTable<int,char>ht1(ht); ht1.PrintHashTable();*/ HashTable<int,char>ht2; ht2.Insert(54,'x'); ht2.Insert(55,'y'); ht2.Insert(56,'z'); ht2.Insert(1,'a'); ht2.Insert(2,'b'); ht2.Insert(3,'c'); ht2.Insert(4,'d'); ht2.Insert(5,'d'); ht2.PrintHashTable(); ht=ht2; ht.PrintHashTable(); } intmain() { TestHashTableBucket(); system("pause"); return0; }原文链接:https://www.f2er.com/datastructure/382506.html