演算法學習筆記(三)——散列表
阿新 • • 發佈:2021-09-13
1.1 散列表(雜湊表)
散列表(雜湊表)是根據鍵值而直接進行訪問的資料結構。通過一個雜湊函式將查詢的鍵轉換為表中的一個索引,來加快查詢的速度。理想情況下,不同的鍵值都能轉化為不同的索引值,但是在現實中,我們常常要處理多個鍵值對應同一個索引值。所以,雜湊查詢的演算法分為兩個部分。第一部分就是關鍵的雜湊函式,第二部分就是處理雜湊衝突。
1.2 雜湊函式
雜湊函式就是通過該函式將元素的鍵值轉換為表的索引。雜湊函式應該易於計算並且能夠均勻分佈所有的鍵,得到的雜湊值應該是一個非負整數,每個不同的鍵都有一一對應的雜湊值。
1.3 雜湊衝突的處理
-
拉鍊法
將表的每一個索引位置都對應一個連結串列,連結串列的每個結點都儲存了對應的鍵值。
-
開放地址法
用大小為M的陣列儲存N個鍵值對(M>N),通過依靠陣列中的空位解決雜湊衝突。最簡單的開放地址法便是線性探測法,當碰撞發生時,我們直接檢查散列表的下一個位置。此時可能有三種結果,命中,未命中或者繼續查詢。
2.程式碼實現
-
基於拉鍊法實現的散列表
template <typename key, typename value> class ChainingListHashTable { private: int N; //鍵值對數量 int M; //散列表的大小 vector<vector<value>> List; int MyHash(key key) { hash<key> hash_key; return (hash_key(key) & 0x7ffffff % M); } public: ChainingListHashTable(int m) { N = 0; M = m; List.resize(m); } value get(key key) { return List[MyHash(key)][0]; } void put(key key, value value) { List[MyHash(key)].push_back(value); N++; } void erase(key key) { value v = MyHash(key); for(int i = 0; i < List[v].size(); ++i) { if(List[v][i]==key) { List[v].erase(List[v].begin()+i); return; } } cerr<<"No such key in List"<<endl; return; } };
-
基於線性探測法的散列表
template <typename key, typename value> class LinearProbingHashTable { private: int N; static int M = 16; vector<key> keys; vector<value> values; int MyHash(key key) { hash<key> hash_key; return (hash_key(key) & 0x7ffffff % M); } void resize(int cap) { keys.resize(cap); values.resize(cap); } bool contains(key key) { for (int i = MyHash(key); keys[i] != NULL; i = (i + 1) % M) { if (keys[i] == key) eturn true; } return false; } public: LinearProbingHashTable() { keys.resize(M); values.resize(M); } void put(key key, value value) { if (N >= M / 2) resize(2 * M); int i; for (i = MyHash(key); keys[i] != NULL; i = (i + 1) % M) { if (keys[i] == key) { values[i] = value; return; } } keys[i] = key; values[i] = value; N++; } value get(key key) { for (int i = MyHash(key); keys[i] != NULL; i = (i + 1) % M) { if (keys[i] == key) return values[i]; } return NULL; } void erase(key Key) { if (!contains(Key)) return; int i = MyHash(Key); while (keys[i] != Key) i = (i + 1) % M; keys[i] = NULL; values[i] = NULL; i = (i + 1) % M; while (keys[i] != NULL) { key keyToRedo = keys[i]; value valueToRedo = values[i]; keys[i] = NULL; values[i] = NULL; N--; put(keyToRedo, valueToRedo); i = (i + 1) % M; } if (N > 0 && N == M / 8) resize(M / 2); } };