數據結構之散列

散列是一種用於以常數平均時間執行插入,刪除和查找的技術git

通常想法

一個關鍵字就是一個帶有相關值的字符串。咱們把表大小記做Table-Size,並將其理解爲散列數據結構的一部分而不單單是浮動於全局的某個標量。
每一個關鍵字被映射到從0到TableSize-1的這個範圍中的某個數,這個映射就叫作散列函數
散列應用:
  • 編譯器中使用散列表跟蹤源代碼。這種數據結構叫作符號表
  • 在遊戲編制過程當中,程序搜索遊戲不一樣行書,它跟蹤經過計算基於位置的散列函數而看到的一些位置。若是一樣的位置再出現,程序一般經過簡單移動變換來避免昂貴的操做。遊戲的這種通常特別叫作變換表
  • 在線拼寫檢驗程序。將整個字典預先散列,單詞則能夠在常數時間內別檢測。
當出現散列值相同的兩個元素時,將產生衝突,下面提供兩種比較簡單的解決方法

分離連接法

作法:將散列的同一個值保留到一張表中。以下圖:算法

1.#include <stdio.h>
2.
3.struct ListNode;
4.typedef struct ListNode *Position;
5.struct HashTbl;
6.typedef struct HashTbl *HashTable;
7.
8.
9.struct ListNode
10.{
11. int Element;
12. Position Next;
13.};
14.
15.typedef Position List;
16.
17.struct HashTbl {
18. int TableSize;
19. List *TheLists;
20.};
21.
22.HashTable InitializeTable(int TableSize) {
23. HashTable H;
24. int i;
25.
26. if (TableSize < 100)
27. {
28. Error("Table size too small");
29. return NULL;
30. }
31. //分配空間
32. H = malloc(sizeof(struct HashTbl));
33. if (H == NULL)
34. {
35. FatalError("Out of space");
36. }
37. //設置表大小爲素數
38. H->TableSize = NextPrime(TableSize);
39. //分配數組空間大小
40. H->TheLists = malloc(sizeof(List)*H->TableSize);
41.
42. //分配表頭
43. for (i = 0; i < H->TableSize; i++)
44. {
45. H->TheLists[i] = malloc(sizeof(struct ListNode));
46. if (H->TheLists[i] == NULL)
47. {
48. FatalError("Out of space");
49. }
50. else
51. {
52. H->TheLists[i]->Next = NULL;
53. }
54.
55. }
56. return H;
57.}
58.
59.//查找
60.Position Find(int Key, HashTable H)
61.{
62. Position P;
63. List L;
64. //獲取表頭
65. L = H->TheLists[Hash(Key, H->TableSize)];
66. P->Next;
67. while (P!=NULL&&P->Element!=Key)
68. {
69. P->Next;
70. }
71. return P;
72.}
73.
74.//插入
75.void Insert(int Key, HashTable H) {
76. Position Pos, NewCell;
77. List L;
78. Pos = Find(Key, H);
79. if (Pos==NULL)
80. {
81. NewCell = malloc(sizeof(struct ListNode));
82. if (NewCell == NULL) {
83.
84. }
85. else
86. {
87. L = H->TheLists[Hash(Key, H->TableSize)];
88. NewCell->Next = L->Next;
89. NewCell->Element = Key;
90. L->Next = NewCell;
91. }
92. }
93.}

開放定址法

分離連接散列算法的缺點是須要指針,因爲給新單元分配地址須要時間,所以這就致使算法的速度有些減慢,同時算法還要對另外一種數據結構的實現。
在開放定址散列算法中,若是有衝突發生,那麼就要嘗試選擇另外的單元,直到找出空單元爲止。
1.#include <stdio.h>
2.typedef unsigned int Index;
3.typedef Index Position;
4.
5.struct HashTbl;
6.typedef struct HashTbl *HashTable;
7.
8.
9.enum KindOfEntry { Legitimate, Empty, Deleted };
10.
11.struct HashEntry
12.{
13. int Element;
14. enum KindOfEntry Info;
15.};
16.
17.typedef struct HashEntry Cell;
18.
19.struct HashTbl
20.{
21. int TableSize;
22. Cell *TheCells;
23.};
24.
25.
26.//初始化
27.HashTable InitializeTable(int TableSize) {
28. HashTable H;
29. int i;
30. if (TableSize < 100)
31. {
32. Error("");
33. return NULL;
34. }
35. H = malloc(sizeof(struct HashTbl));
36. if (H == NULL)
37. {
38. FatalError("");
39. }
40. H->TableSize = NextPrime(TableSize);
41. H->TheCells = malloc(sizeof(Cell)*H->TableSize);
42. if (H->TheCells == NULL)
43. {
44. FatalError("!!!");
45. }
46. for (i = 0; i < H->TableSize; i++)
47. {
48. H->TheCells[i].Info = Empty;
49. }
50. return H;
51.}
52.
53.
54.Position Find(int Key, HashTable H) {
55. Position CurrentPos;
56. int CollisitionNum;
57. CollisitionNum = 0;
58. CurrentPos = Hash(Key, H->TableSize);
59. while (H->TheCells[CurrentPos].Info != NULL&&H->TheCells[CurrentPos].Element != Key)
60. {
61. CurrentPos += 2 * ++CollisitionNum - 1;
62. if (CurrentPos >= H->TableSize)
63. {
64. CurrentPos -= H->TableSize;
65. }
66. }
67. return CurrentPos;
68.}
69.
70.
71.void Insert(int Key, HashTable H)
72.{
73. Position Pos;
74. Pos = Find(Key, H);
75. if (H->TheCells[Pos].Info=Legitimate)
76. {
77. H->TheCells[Pos].Info = Legitimate;
78. H->TheCells[Pos].Element = Key;
79. }
80.}
81.
82.//再散列
83.HashTable Rehash(HashTable H)
84.{
85. int i, OldSize;
86. Cell *OldCells;
87.
88. OldCells = H->TheCells;
89. OldSize = H->TableSize;
90.
91.
92. H = InitializeTable(2 * OldSize);
93.
94. for (i=0; i < OldSize; i++)
95. {
96. if (OldCells[i].Info == Legitimate)
97. {
98. Insert(OldCells[i].Element, H);
99. }
100. }
101. free(OldCells);
102. return H;
103.}

再散列

原始表達到某一個邊際值的時候,創建另一個大約2倍大的表,掃描整個原始表,計算每一個元素的新散列值並插入到新表中。
再散列是一種很是昂貴的操做。
實現方法:
  • 只要表填滿到一半就再散列
  • 只要當插入失敗就再散列
  • 當表到達某一個裝填因子時進行在散列
再散列還能夠用在其餘數據結構中,好比:隊列。

可擴散列

和B-樹相似。數組

相關文章
相關標籤/搜索