構造哈希表經常使用的方法是:ios
除留餘數法--取關鍵值被某個不大於散列表長m的數p除後的所得的餘數爲散列地址。HashKey= Key % P。ide
直接定址法--取關鍵字的某個線性函數爲散列地址HashKey= Key 或 HashKey= A*Key + BA、B爲常數。函數
我在這裏主要使用一下除留餘數法Hash(key) =Key%P,(P這裏是哈希表的長度)p最好是素數考慮下降哈希衝突的緣由,我並無在這上面過於追究此處哈希表長度10,見線性探測圖。測試
哈希表常常遇到的一個問題就是哈希衝突。spa
哈希衝突是什麼呢?哈希衝突指的是:不一樣的關鍵字通過相同的哈希函數映射到相同的的哈希地址處。對象
要解決哈希衝突閉散列方法主要有兩個:線性探測與二次探測。blog
在這裏,我將線性探測的原理用下圖表述:ci
線性探測get
線性探測代碼以下:string
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; #include<string> //線性探測的特化處理能夠處理自定義類型的數據 enum State { EMPTY,//該位置未存放元素 DELETE,//該位置元素已被刪除 EXIST,//該位置存在元素 }; //處理基本類型 template<class K> struct DefaultFuncer { size_t operator()(const K& key) { return key; } }; //處理自定義類型 template<> struct DefaultFuncer<string> { size_t value = 0; size_t operator()(const string& str) { for (int i = 0; i < str.size(); i++) { value += str[i]; } return value; } }; template<class K, template<class>class HashFuncer = DefaultFuncer> class HashTable { public: HashTable() :_size(0) , _capacity(0) , _state(NULL) , _table(NULL) {} HashTable(size_t size) :_size(0) , _capacity(size) , _state(new State[size]) , _table(new K[size]) { for (int i = 0; i < _capacity; i++)//所有狀態初始化成EMPTY { _state[i] = EMPTY; } } //線性探測計算出元素存放位置(假設不哈希衝突) int _HashFunc(const K& key) { HashFuncer<K> hf; return hf(key) % _capacity; //匿名對象調用operator() /*return HashFuncer<K>()(key) % _capacity;*/ } void Swap(HashTable<K> tmp) { swap(_size, tmp._size); swap(_capacity, tmp._capacity); swap(_state, tmp._state); swap(_table, tmp._table); } void _CheckCapacity() { HashTable<K> tmp(2*_capacity); for (int i = 0; i < _capacity; i++) { tmp.Insert(_table[i]); } Swap(tmp); } bool Insert(const K& key) { //靜態哈希表 /*if (_size == _capacity) { cout<<"HashTable is full!"<<endl; return false; }*/ //動態哈希表 //高效哈希表的載荷因子大概穩定在0.7-0.8較好 if (10 * _size >= 7 * _capacity) { _CheckCapacity(); } int index = _HashFunc(key); while (_state[index] == EXIST) { index++; if (index == _capacity) { index = 0; } } _table[index] = key; _state[index] = EXIST; _size++; return true; } int Find(const K& key) { int index = _HashFunc(key); while (_state[index] == EXIST || _state[index]== DELETE) //while(_state[index] != EMPTY) //空狀態找不到,非空狀態找獲得 { if (_table[index] == key && _state[index] == EXIST) { return index; } ++index; if (index == _capacity) { index = 0; } } return -1; } bool Remove(const K& key) { int index = Find(key); if (index != -1) { _state[index] = DELETE; --_size; return true; } return false; } void PrintTable() { for (int i = 0; i < _capacity; i++) { if (_state[i] == EXIST ) { cout << i << "(EXIST):" << _table[i] << endl; } /*我將DELETE狀態元素也打印出來,便於觀察。 而Insert處理時,DELETE狀態下的位置能夠插上新的元素*/ else if (_state[i] == DELETE) { cout << i << "(DELETE):" << _table[i] << endl; } else { cout << i << "(EMPTY):" << _table[i] << endl; } } } private: size_t _size;//實際存放元素個數 size_t _capacity;//哈希表長度 State* _state; K* _table; }; //POD(基本類型)的測試用例 void TestHashTablePOD() { HashTable<int> ht(10); ht.Insert(89); ht.Insert(18); ht.Insert(49); ht.Insert(58); ht.Insert(9); ht.PrintTable(); int ret = ht.Find(89); cout << ret << endl; ht.Remove(89); ht.PrintTable(); ht.Remove(18); ht.PrintTable(); } //自定義類型的測試用例 void TestHashTable() { HashTable<string,DefaultFuncer> ht(10); ht.Insert("信息化"); ht.Insert("時代"); ht.Insert("電腦"); ht.Insert("測試工程師"); ht.PrintTable(); int ret = ht.Find("測試工程師"); cout << ret << endl; ht.Remove("電腦"); ht.PrintTable(); ht.Remove("時代"); ht.PrintTable(); } int main() { TestHashTable(); system("pause"); return 0; }