哈希表

一.符號表問題數組

1.一個表裏面放着n條記錄,(記錄x:x一般是一個指向實際數據的指針)數據結構

2.在每一個記錄中,存在一個記錄的鍵,還存在一些衛星數據(屬於鍵的附加數據)ide

3.排序是對記錄進行排序,而不是關鍵字函數

4.對錶進行操做:添加記錄,刪除記錄,查找具備特定鍵的記錄spa

 

二.直接映射表(數組)設計

1.適用於關鍵字的全域(可能存儲的關鍵字)較小的狀況3d

2.數組的每一個位置對應全域中的一個關鍵字,關鍵字k的元素被存放在槽k中  指針

3.缺陷:若是關鍵字只有幾千,而關鍵字的全域需64位來表示,致使大量空槽code

 1 class direct_address_table:
 2     '''直接尋址表'''
 3     def __init__(self, T=[], size=0):
 4         if len(T) == 0:
 5             self.T = [None for i in range(size)]
 6         else:
 7             self.T = T
 8         self.size = size
 9     '''對於節點'''
10     def search(self, k):
11         return self.T[k]
12 
13     def insert(self, x):
14         self.T[x.key] = x
15 
16     def delete(self, x):
17         self.T[x.key] = None
18 
19 class Node:
20     def __init__(self, key):
21         self.key = key
22 
23 T=[]
24 dat=direct_address_table(T,10)
25 x=Node(2)
26 print(dat.insert(x))
直接尋址表

 

三.哈希表(散列表)(Hash Table)(一個長度與實際存儲關鍵字數目成比例的數組)blog

1.哈希法:用一個hash函數來隨機映射那些鍵到哈希表T的槽

2.哈希表是一種根據關鍵字,計算相應的存儲位置,訪問數據的數據結構,

3.適用於:實際存儲的關鍵字數目比所有的可能關鍵字總數較少時

4.利用哈希函數(hash function)h,把原來具備關鍵字k的元素存放在槽k中變成該元素放在h(k)中

 

三.哈希函數

一個好的哈希函數:每一個關鍵字都被等可能地哈希到m個槽位中的任何一個,並與其餘關鍵字已散列到哪一個槽位無關

(1)除法散列法:用一個特定的素數m來除所給的關鍵字,h(k)=k mod m ,k爲關鍵字,m爲散列表大小並且不能過小,m通常不爲2的冪或10的冪等類似的

(2)乘法散列法:對m的選擇不是特別關鍵,通常爲2的冪,A不要太接近以2爲底的數

(3)全域散列法:從一組精心設計的函數中,隨機地選擇一個做爲散列函數,使之獨立於要存儲的關鍵字

 

三.衝突:多個關鍵字映射到數組的同一下標

 解決衝突:

(1)連接法:把相同的哈希值的記錄放到一個鏈表裏存儲

最壞狀況分析:全部鍵映射到同一個槽,訪問θ(n)

平均狀況分析:假設簡單均勻哈希(每一個屬於集合的鍵都有相同的概率被哈希映射到表的任意一個槽中),每一個鍵與其餘的鍵相互獨立

 

1是把鍵只哈希映射到槽所須要的時間,α是搜索槽對應的鏈表所花費的時間

 1 class chained_hash:
 2     '''連接法散列,查找和插入時都要判斷槽中有沒有元素'''
 3     def __init__(self, T=[], size=0):
 4         if len(T) == 0:
 5             self.T = [None for i in range(size)]
 6         else:
 7             self.T = T
 8         self.size = size
 9     def search(self, k):
10         if self.T[self.hash_h(k)] != None:
11             x = self.T[self.hash_h(k)].list_search(k)
12             return x
13         return None
14     def insert(self, x):
15         if self.T[self.hash_h(x.key)] == None:
16             self.T[self.hash_h(x.key)] = DoublyLinkedList(x)
17         else:
18             self.T[self.hash_h(x.key)].list_insert(x)
19     def delete(self, x):
20         self.T[self.hash_h(x.key)].list_delete(x)
21     def hash_h(self, key):
22         '''hash函數'''
23         return key % 12
24 
25 class Node:
26     def __init__(self, key):
27         self.key = key
28 class DoublyNode:
29     def __init__(self, n_prev, n_next, key):
30         self.prev = n_prev
31         self.next = n_next
32         self.key = key
33 
34 class DoublyLinkedList:
35     def __init__(self, head):
36         self.head = head
37 
38     def list_search(self, k):
39         x = self.head
40         while x != None and x.key != k:
41             x = x.next
42         return x
43 
44     def list_insert(self, x):
45         x.next = self.head
46         if self.head != None:
47             self.head.prev = x
48         self.head = x
49         x.prev = None
50 
51     def list_delete(self, x):
52         if x.prev != None:
53             x.prev.next = x.next
54         else:
55             self.head = x.next
56         if x.next != None:
57             x.next.prev = x.prev
58 
59 T=[]
60 x=DoublyNode(None,None,13)
61 ch=chained_hash(T,12)
62 ch.insert(x)
63 x=DoublyNode(None,None,25)
64 ch.insert(x)
65 y=ch.search(25)
66 print(y.key)
67 
68 ch.delete(y)
69 print(ch.T[1].head)
70 print(ch.T[1].head.key)
71 print(ch.T[1].head.next)
72 -----------------------------------------
73 25
74 <__main__.DoublyNode object at 0x039C78B0>
75 13
76 None
連接法散列

(2)開放尋址法:全部元素都存放在散列表中,系統地探查哈希表直到找到空槽

探查:連續地檢查散列表,來找到空槽放置待插入的關鍵字

計算開放尋址中的探查序列:

(1)線性探查:h(k,i)=(h'(k)+i)mod m ,i=1...m-1

(2)二次探查:h(k,i)=(h'(k)+c1 i+c2 i*2)mod m, 

(3)雙重散列:(h1(k)+ih2(k))mod m 

 1 class open_address_hash:
 2     '''開放尋址散列,散列表T和一個關鍵字k'''
 3     def __init__(self, T=[], size=0):
 4         if len(T) == 0:
 5             self.T = [None for i in range(size)]
 6         else:
 7             self.T = T
 8         self.size = size
 9 
10     def hash_insert(self, k):
11         '''插入關鍵字k,返回k的插槽或已滿標誌'''
12         i = 0
13         while i < self.size:
14             j = self.hash_h1_h2(k, i)#搜尋空槽並插入
15             if self.T[j] == None:
16                 self.T[j] = k
17                 return j
18             else:
19                 i += 1
20         return "hash table overflow"
21 
22     def hash_search(self, k):
23         '''查找,若是槽j包含了關鍵字k,則返回j,不然返回NOne'''
24         i = 0
25         j = self.hash_h1_h2(k, i)
26         while self.T[j] != None and i < self.size:
27             j = self.hash_h1_h2(k, i)
28             if self.T[j] == k:
29                 return j
30             else:
31                 i += 1
32         return None
33 
34     def hash_h1_h2(self, k, i):
35         '''hash 函數'''
36         return ((k % self.size + i * (1 + k % (self.size - 2)))) % self.size
37 
38 T=[]
39 oah=open_address_hash(T,13)
40 print(oah.hash_insert(79))
41 print(oah.hash_insert(69))
42 print(oah.hash_search(50))
43 ------------------------------
44 1
45 4
46 None
開放地址散列

 

四.全域哈希和徹底哈希

1.哈希的根本缺陷:對任意哈希函數,都存在一個很差的鍵集,全部鍵都會哈希映射到同一個槽

2.全域哈希:隨機選擇哈希函數,使之獨立於要存儲的關鍵字

相關文章
相關標籤/搜索