在上篇博客中,已经提出了两种解决哈希冲突的办法:线性探测,二次探测。
下面呢,在介绍一种解决冲突的办法---开链法(哈希桶)
哈希桶的实现:主要是将哈希冲突的那些值存到链表中。
代码实现:(支持字典查询)
#pragma once #include <iostream> #include <vector> #include <string> using namespace std; template <class T,class V> struct HashTableNode { HashTableNode(const T& key,const V& value) :_key(key) ,_value(value) ,_next(NULL) {} T _key; V _value; HashTableNode<T,V>* _next; }; template <class T> struct __HashFunc { size_t operator()(const T& key) { return key; } }; template <> struct __HashFunc<string> { size_t operator()(const string& key) { size_t hash = 0; for(size_t i=0;i<key.size();++i) { hash += key[i]; } return hash; } }; template <class T,class V,class HashFunc = __HashFunc<T>> class HashTableBucket //哈希桶 { typedef HashTableNode<T,V> Node; typedef HashTableBucket<T,V,HashFunc> Table; public: //构造 HashTableBucket() :_table(NULL) ,_size(0) {} HashTableBucket(size_t capacity) :_size(0) { _table.resize(_CheckCapacity(capacity)); } //析构 ~HashTableBucket() { for(size_t i=0;i<_table.size();++i) { Node* cur = _table[i]; while(cur) { Node* del = cur; cur = cur->_next; delete del; } _table[i] = NULL; } } //拷贝 HashTableBucket(const Table& ht) :_size(0) { _table.resize(ht._table.size()); //开辟空间 for(size_t i=0;i<ht._table.size();++i) { Node* cur = ht._table[i]; while(cur) { Insert(cur->_key,cur->_value); cur = cur->_next; } } } //赋值 /*HashTableBucket<T,V>& operator=(HashTableBucket<T,V> ht) { _table.swap(ht._table); swap(_size,ht._size); return *this; }*/ Table& operator=(Table& ht) { if(this != &ht) { Table tmp(ht); _table.swap(tmp._table); swap(_size,tmp._size); } return *this; } public: bool Insert(const T& key,const V& value) { _CheckCapacity();//检查容量 size_t index = _HashFunc(key,_table.size()); Node* cur = _table[index]; while(cur) { if(cur->_key == key) //防冗余 { return false; } cur = cur->_next; } //头插 Node* newNode =new Node(key,value); newNode->_next = _table[index]; _table[index] = newNode; ++_size; return true; } Node* Find(const T& key) { size_t index = _HashFunc(key,_table.size()); Node* cur = _table[index]; while(cur) { if(cur->_key == key) { return cur; } cur = cur->_next; } return NULL; } bool Remove(const T& key) { size_t index = _HashFunc(key,_table.size()); Node* cur = _table[index]; Node* prev = NULL; Node* del = NULL; if(cur->_key == key) { del = cur; _table[index] = cur->_next; delete del; return true; } prev = cur; cur = cur->_next; while(cur) { if(cur->_key == key) { del = cur; prev->_next = cur->_next; delete del; return true; } prev = cur; cur = cur->_next; } return false; } void Print() { for(size_t i=0;i<_table.size();++i) { printf("_table[%d]:",i); Node* cur = _table[i]; while(cur) { cout<<"["<<cur->_key<<","<<cur->_value<<"]"<<"->"; cur = cur->_next; } cout<<"NULL"<<endl; } } protected: size_t _HashFunc(const T& key,size_t capacity) //哈希函数 { //return key%capacity; HashFunc hash; return hash(key)%capacity; } size_t _GetNextPrime(const size_t size) //获取下一个素数 { // 使用素数表对齐做哈希表的容量,降低哈希冲突 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] > size) { return _PrimeList[i]; } } return _PrimeList[_PrimeSize-1]; } void _CheckCapacity() { if(_size == _table.size()) { size_t nextPrime = _GetNextPrime(_size); vector<Node*> newtable; newtable.resize(nextPrime); for(size_t i=0;i<_table.size();++i) { Node* cur = _table[i]; while(cur) { //摘节点 Node* tmp = cur; cur = cur->_next; //计算在新表中的位置,头插 size_t index = _HashFunc(tmp->_key,nextPrime); newtable[index] = tmp; } _table[i] = NULL; } _table.swap(newtable); //size,capacity,内容 } } private: vector<Node*> _table; //哈希表 size_t _size; //数据的个数 };
测试代码:
#include "HashTableBucket.h" void HashTableListTest() { HashTableBucket<int,int> ht; for(size_t i=0;i<50;++i) { ht.Insert(i,i); } ht.Insert(107,32); ht.Insert(54,45); //ht.Insert(65,32); /*HashTableNode<int,int>* ret = ht.Find(1); if(ret) { cout<<"["<<ret->_key<<","<<ret->_value<<"]"<<endl; }*/ //ht.Remove(54); ht.Remove(1); //ht.Print(); } void HashTableTest() { HashTableBucket<int,int> ht; ht.Insert(1,1); ht.Insert(11,11); ht.Insert(21,21); ht.Insert(12,12); ht.Insert(23,23); ht.Insert(54,57); ht.Insert(42,12); //ht.Print(); HashTableBucket<int,int> ht1(ht); //ht1.Print(); HashTableBucket<int,int> ht2; ht2 = ht1; ht2.Print(); } void DircFindTest() { HashTableBucket<string,string> ht; /*ht.Insert("zhang","张"); ht.Insert("xiao","小"); ht.Insert("yu","雨");*/ //ht.Insert("angzh","田"); ht.Insert("字典","dirc"); ht.Insert("钱","money"); ht.Insert("吃","eat"); ht.Insert("玩","happy"); ht.Print(); }
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。