哈希表>
哈希表也叫散列表,是依据关键码值(key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中的一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫散列表.
了解了什仫是哈希表之后,我们发现哈希表这种数据结构是类似于线性表的,只是表中的元素不是精密排列的,而是可能存在空间.
比如我们存储70个元素,但是我们可能为这70个空间申请了100个元素的
空间,70/100=0.7,这个数字称为负载因子(有的书中也叫载荷因子),x(负载因子)=填入表中的元素个数/散列表的长度,之所以存在负载因子是为了"高速存取"的目的.我们基于一种结果尽可能的随机平均分布的固定函数H为每一个元素安排存储位置,这样就能够避免遍历性质的线性搜索,以达到高速存取,但是这个结果是随机的,也必定导致冲突.
哈希冲突/哈希碰撞>
不同的key值经过哈希函数处理后可能产生相同的值哈希地址,这种情况就叫做哈希冲突,任意的散列函数都不能避免哈希冲突.
如何解决哈希冲突的情况呢?闭散列方法(开放定址法).,开链法/拉链法(哈希桶)
一.闭散列方法(开放定址法)>
1).线性探测>
2).二次探测>
3).双散列方法>
顾名思义双散列就是有两个散列地址,用第一个哈希函数解决不了冲突域时,用第二个继续计算,只到冲突域解决为止.双散列法优于二次探测法
二.开链法/拉链法(哈希桶)
对关键码集合用一个散列函数计算他们存放的位置.将散列表地址相同的元素放到一个集合中,用链表链接起来.
在我的代码实现中用到的解决哈希冲突的方法是闭散列中的线性探测法和拉链法,值得注意的是:降低哈希冲突最好使用素数做哈希表的容量(用素数做除数可以减少哈希冲突).
构造散列函数的方法>
1).直接寻址法>
取关键字或关键字的某个线性函数值为散列地址.H(key)=key或H(key)=a*key+b,其中a,b为常数(这种散列函数叫做自身函数).若其中H(key)中已经存在数据,就往下一个找,直到H(key)中没有值了,就放进去.
2).除留余数法>
取key被不大于散列表表长m的数p除后所得的余数为散列地址.Hash(key)=key%p;
3).数字分析法
4).平方取中法
5).折叠法
6).随机数法
更详细的介绍见>http://url.cn/416R94i
解决哈希冲突的闭散列法
namespace HashTable { enum Status { EMPTY, EXIST, DELECT, }; template<class K,class V> struct HashNode { K _key; V _value; Status _status; HashNode(const K& key=K(),const V& value=V()) :_key(key) ,_value(value) ,_status(EMPTY) {} }; template<class K> struct __HashFunc { size_t operator()(const K& key) { return key; } }; //特化 template<> struct __HashFunc<string> { static size_t BKDRHash(const char*str) { unsigned int seed= 131;// 31 131 1313 13131 131313 unsigned int hash= 0; while(*str) { hash = hash * seed + (*str++); } return(hash& 0x7FFFFFFF); } size_t operator()(const string& str) { return BKDRHash(str.c_str()); } }; template<class K,class V,class HashFunc=__HashFunc<K>> class HashTables { typedef HashNode<K,V> Node; public: HashTables() :_size(0) { _tables.resize(_GetPrime(0)); } HashTables(const HashTables<K,V,HashFunc>& hash) { size_t size=hash._tables.size(); _tables.resize(size); for (size_t i=0;i<_tables.size();++i) { if (hash._tables[i]._status == EXIST) { _tables[i]._key=hash._tables[i]._key; _tables[i]._value=hash._tables[i]._value; _tables[i]._status=hash._tables[i]._status; } } _size=hash._size; } HashTables<K,V,HashFunc>& operator=(const HashTables<K,V,HashFunc>& hash) { if (this != &hash) { HashTables<K,V,HashFunc> tmp(hash); _Swap(tmp); } return *this; } public: bool Insert(const K& key,const V& value) { _CheckSize(); size_t index=_GetPosition(key); while (_tables[index]._status == EXIST) { if (_tables[index]._key == key) { _tables[index]._value++; _size++; return false; } ++index; if(index == _tables.size()) index=0; } _tables[index]._key=key; _tables[index]._value=value; _tables[index]._status=EXIST; _size++; return true; } void Delete(const K& key) //伪删除法 { Node *ret=Find(key); if (ret != NULL) { ret->_status=DELECT; _size--; } } Node *Find(const K& key) { size_t index=_GetPosition(key); size_t src=index; while (_tables[index]._status != EMPTY) { if (_tables[index]._key == key) { if (_tables[index]._status == DELECT) return NULL; else return &_tables[index]; } ++index; if(index == src) break; } return NULL; } void Display() { for (size_t i=0;i<_tables.size();++i) { if (_tables[i]._status == EXIST) { cout<<_tables[i]._key<<" "; } } cout<<endl; } protected: void _CheckSize() { if (_tables.size() == 0 || _size*10/_tables.size() >= 8) { size_t NewSize=_GetPrime(_tables.size()); HashTables<K,V,HashFunc> hashTable; //现代的写法 hashTable._tables.resize(NewSize); for (size_t i=0;i<_tables.size();++i) { if(_tables[i]._status == EXIST) { hashTable.Insert(_tables[i]._key,_tables[i]._value); } } _Swap(hashTable); } } void _Swap(HashTables<K,V,HashFunc> hash) { _tables.swap(hash._tables); swap(_size,hash._size); } size_t _GetPrime(size_t num) { const int _PrimeSize= 28; //素数表 static const unsigned long _PrimeList[_PrimeSize] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; for (size_t i=0;i<_PrimeSize;++i) { if(_PrimeList[i] > num) return _PrimeList[i]; else continue; } return _PrimeList[_PrimeSize-1]; } size_t _GetPosition(const K& key) //除留余数法 { HashFunc hf; return hf(key)%_tables.size(); } protected: vector<Node> _tables; size_t _size; }; }
解决哈希冲突的拉链法>
namespace HashTable_List { template<class K,class V> struct HashNode { K _key; V _value; HashNode<K,V> *_next; HashNode(const K& key=K(),const V& value=V()) :_key(key) ,_value(value) ,_next(NULL) {} }; template<class K> struct __HashFunc { size_t operator()(const K& key) { return key; } }; //偏特化 template<> struct __HashFunc<string> { static size_t BKDRHash(const char*str) { unsigned int seed= 131;// 31 131 1313 13131 131313 unsigned int hash= 0; while(*str) { hash = hash * seed + (*str++); } return(hash& 0x7FFFFFFF); } size_t operator()(const string& str) { return BKDRHash(str.c_str()); } }; template<class K,class V,class HashFunc=__HashFunc<K>> class HashTable { typedef HashNode<K,V> Node; public: HashTable() :_size(0) {} HashTable(const HashTable<K,V,HashFunc>& hash) { _table.resize(hash._table.size()); for (size_t i=0;i<hash._table.size();++i) { Node *cur=_table[i]; while (cur) { Insert(cur->_key,cur->_value); cur=cur->_next; } } } HashTable<K,V,HashFunc>& operator=(const HashTable<K,V,HashFunc>& hash) { if (this != &hash) { HashTable<K,V,HashFunc> tmp(hash); _Swap(hash); } return *this; } ~HashTable() { for (size_t i=0;i<_table.size();++i) { Node *cur=_table[i]; Node *del=NULL; while (cur) { del=cur; cur=cur->_next; delete del; del=NULL; } } _size=0; _table.clear(); } public: Node *Find(const K& key) { int index=_GetPosition(key,_table.size()); Node *cur=_table[index]; while (cur) { if(cur->_key == key) { return cur; } cur=cur->_next; } return NULL; } bool Insert(const K& key,const V& value) { //头插 _CheckSize(); size_t index=_GetPosition(key,_table.size()); Node *ret=Find(key); if(ret) //插入的元素已经存在 { ret->_value++; _size++; return false; } Node *NewNode=new Node(key,value); NewNode->_next=_table[index]; _table[index]=NewNode; _size++; return true; } bool Remove(const K& key) { Node *prev=NULL; int index=_GetPosition(key,_table.size()); Node *cur=_table[index]; while (cur) { if(cur->_key == key) { if (prev == NULL) //删除的是第一个结点 _table[index]=cur->_next; else //删除尾结点,删除中间节点 prev->_next=cur->_next; delete cur; cur=NULL; _size--; return true; } prev=cur; cur=cur->_next; } return false; } void Display() { for (size_t i=0;i<_table.size();++i) { Node *cur=_table[i]; cout<<i<<":"; while (cur) { cout<<cur->_key<<" "; cur=cur->_next; } cout<<endl; } } protected: size_t _GetPrime(size_t num) { const int _PrimeSize= 28; //素数表 static const unsigned long _PrimeList[_PrimeSize] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; for (size_t i=0;i<_PrimeSize;++i) { if(_PrimeList[i] > num) return _PrimeList[i]; else continue; } return _PrimeList[_PrimeSize-1]; } void _CheckSize() { if (_size == 0 || _size == _table.size()) { vector<Node *> tmp; tmp.resize(_GetPrime(_table.size())); for (size_t i=0;i<_table.size();++i) { Node *cur=_table[i]; while (cur) { Node *next=cur->_next; size_t index=_GetPosition(cur->_key,tmp.size()); cur->_next=tmp[index]; tmp[index]=cur; cur=next; } } tmp.swap(_table); } } void _Swap(HashTable<K,V,HashFunc> hash) { _table.swap(hash._table); swap(_size,hash._size); } size_t _GetPosition(const K& key,size_t size) { HashFunc hf; return hf(key)%size; } protected: vector<Node *> _table; size_t _size; }; }