1. 程式人生 > 實用技巧 >15.模擬散列表 雜湊表

15.模擬散列表 雜湊表

雜湊表的時間複雜度近似O(1)

什麼情況下需要用到雜湊表

把一個龐大的值域,對映到一個較小的(10 ^ 5 ~ 10 ^ 6左右)值域

之前的離散化是一種極其特殊的雜湊方式,之前的離散化需要保序的,需要保證單調遞增

現在說的是一般意義的雜湊

定義一個雜湊函式h()

使得h(x)的值域屬於0 ~ 10 ^ 5, x的取值範圍是 -10 ^ 9 ~ 10 ^ 9

一般情況下,雜湊函式可以直接取模

然後還需要處理一下衝突的問題

如果兩個不同的數經過雜湊函式之後,對映成了相同的一個數如何解決

按照處理衝突的方式,把雜湊表分為兩種,開放定址法和拉鍊法

拉鍊法:

圖論裡面存點的時候,用到的儲存結構和拉鍊法相同

首先開個一維陣列,來儲存所有的雜湊值

每一個槽上拉一條鏈(單鏈表),來儲存這個槽上當前有的所有數

一般情況下,演算法題目不需要在雜湊表中刪除元素。一般只有新增和查詢兩個操作

如果真要刪除,不是真正的把這個元素從表中刪除。可以再開一個數組,打一個標記,表示這個點被刪除了

拉鍊法程式碼

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 //拉鍊法
 4 const int N = 100003;
 5 //取模的時候要取質數,而且要離2的整次冪儘可能遠
 6 //這樣衝突的概率最小
 7 int h[N], e[N], ne[N], idx;
8 //h陣列是槽,其餘和單鏈表一樣 9 void insert(int x) { //插入操作 10 int k = (x % N + N) % N; 11 //k是雜湊值 12 e[idx] = x; 13 ne[idx] = h[k]; //頭插法 14 h[k] = idx; 15 idx++; 16 } 17 bool find(int x) { //查詢操作 18 int k = (x % N + N) % N; 19 for (int i = h[k]; i != -1; i = ne[i]) { 20 if (e[i] == x) {
21 return true; 22 } 23 } 24 return false; 25 } 26 int main() { 27 memset(h, -1, sizeof(h)); //把所有槽清空,單鏈表的空指標用-1表示 28 int n; 29 cin >> n; 30 while (n--) { 31 string op; 32 int x; 33 cin >> op; 34 if (op == "I") { 35 cin >> x; 36 insert(x); 37 } else { 38 cin >> x; 39 if (find(x)) { //如果能找到x這個數的話 40 cout << "Yes" << endl; 41 } else { 42 cout << "No" << endl; 43 } 44 } 45 } 46 return 0; 47 }

開放定址法:

只開一維陣列

這個一維陣列的長度,經驗上看,要開到題目資料範圍的2 ~ 3倍

開放定址法處理衝突的思路是:衝突了就往後找,知直到空了

開放定址法程式碼

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 200003, null = 0x3f3f3f3f;
 4 //如果陣列上的數是null的話,表示這個位置上是空
 5 //這個數只要不在題目的資料範圍內就好了
 6 int h[N];
 7 int find(int x) {
 8     //如果x在雜湊表中已經存在的話,返回x所在的位置
 9     //如果x在雜湊表中不存在的話,返回x應該儲存的位置
10     int k = (x % N + N) % N;
11     while (h[k] != null && h[k] != x) {
12         k++;
13         if (k == N) {
14             k = 0;
15         }
16     }
17     return k;
18 }
19 int main() {
20     memset(h, 0x3f, sizeof(h));
21     int n;
22     cin >> n;
23     while (n--) {
24         string op;
25         int x;
26         cin >> op >> x;
27         if (op == "I") {
28             int k = find(x);
29             h[k] = x; 
30         } else {
31             int k = find(x);
32             if (h[k] != null) {
33                 cout << "Yes" << endl;
34             } else {
35                 cout << "No" << endl;
36             }
37         }
38     }
39     return 0;
40 }