少年,不知道你好記不記得第三篇文章講python內建數據結構的方法及其時間複雜度時裏面關於dict與set的時間複雜度[爲什麼訪問元素爲O(1)]原理我說後面講嗎?其實就是這篇文章講啦。html
目錄:python
一:Hash的定義算法
二:dict與set的實現原理數據結構
三:經常使用構造hash函數的方法ide
四:hash碰撞及其解決方法函數
五:dict的實現spa
一:Hash的定義翻譯
Hash,通常翻譯作「散列」,就是把任意長度的輸入,經過散列算法,變換成固定長度的輸出,該輸出就是散列值。【不一樣的輸入可能會散列成相同的輸出,因此不可能從散列值來惟一的肯定輸入值】3d
二:dict與set的實現原理指針
dict與set實現原理是同樣的,都是將實際的值放到list中。惟一不一樣的在於hash函數操做的對象,對於dict,hash函數操做的是其key,而對於set是直接操做的它的元素,假設操做內容爲x,其做爲因變量,放入hash函數,經過運算後取list的餘數,轉化爲一個list的下標,此下標位置對於set而言用來放其自己,而對於dict則是建立了兩個list,一個list該下表放此key,另外一個list中該下標方對應的value。
其中,咱們把實現set的方式叫作Hash Set,實現dict的方式叫作Hash Map/Table(注:map指的就是經過key來尋找value的過程)
三:經常使用構造hash函數的方法
1:摺疊法
將每一個元素分爲相等的幾部分後相加後再除以list長度,e.g:若是項目是436-555-4601, 以2爲分組,分紅了 (43, 65, 55, 46, 01). 所有加起來:43 + 65 + 55 + 46 + 01 = 210. 假設list有11個元素, 則210%11 =1, 因此將436-555-4601放到list下標爲1的地方。
2:取中法:
如元素44平方後得1936取中93再取list的餘
注:對於string其所對應的數字可用其ASCII碼來代替(還可與位數結合,見圖5.7)ord('a')可返回'a'的ASCII碼
注:此地就是爲何dict與set訪問元素時間複雜度爲O(1)的緣由了,經過對元素的hash函數運算後可以直接知道其下標,因此爲O(1)
四:hash碰撞及其解決方法
定義裏面講到過不一樣的輸入可能會散列成相同的輸出,因此就可能出現名爲「哈希碰撞」的狀況,也就是說兩個不一樣的元素算出來的下標值同樣,此時就有兩種解決方法:
1:向後探測
架設一個元素算出來下標爲5,另外一個元素算出來下標也爲5,從開頭開始探測第0第1位是否爲空,當看到爲空的就放入,不過這樣相鄰探測的很差之處在於容易發生彙集,因此最好是跳躍着進行探測,定義一個skip的值,好比3,用方程rehash(pos) = (pos + skip)%sizeoftable,即便查看0,3,6這樣跳躍着來
2:鏈式存儲
原理圖以下,其實就是將發生有衝突的元素放到同一位置,而後經過「指針「來串聯起來
五:HashTable
下面將寫一個hashTable,而實際中的dict就是由hashTable擴展而來的
1 class HashTable: 2 def __init__(self): 3 self.size = 11 4 self.slots = [None] * self.size 5 self.data = [None] * self.size 6 7 def hash_function(self, key, size): 8 return key % size 9 def rehash(self, old_hash, size): 10 return (old_hash + 1) % size 11 def __getitem__(self, key): 12 return self.get(key) 13 def __setitem__(self, key, data): 14 self.put(key, data) 15 16 def put(self, key, data): 17 hash_value = self.hash_function(key,len(self.slots)) 18 if self.slots[hash_value] == None: 19 self.slots[hash_value] = key 20 self.data[hash_value] = data 21 elif self.slots[hash_value] == key: 22 self.data[hash_value] = data # replace 23 else: 24 next_slot = self.rehash(hash_value, len(self.slots)) 25 while self.slots[next_slot] != None and self.slots[next_slot] != key: 26 next_slot = self.rehash(next_slot, len(self.slots)) 27 if self.slots[next_slot] == None: 28 self.slots[next_slot] = key 29 self.data[next_slot] = data 30 else: 31 self.data[next_slot] = data #replace 32 33 def get(self, key): 34 start_slot = self.hash_function(key, len(self.slots)) 35 data = None 36 stop = False 37 found = False 38 position = start_slot 39 while self.slots[position] != None and not found and not stop: 40 if self.slots[position] == key: 41 found = True 42 data = self.data[position] 43 else: 44 position=self.rehash(position, len(self.slots)) 45 if position == start_slot: 46 stop = True 47 return data