哈希表能夠表述爲,是一種能夠根據關鍵字快速查詢數據的數據結構python
不論哈希表中數據有多少,增長,刪除,改寫數據的複雜度平均都是O(1),效率很是高數組
1. 哈希表原理數據結構
若是說每個數據它都對應着一個固定的位置,那咱們查找特定一個數據時,就能夠直接查看這個數據對應的位置是否存在數據。一個形象的例子就是學生在教室中的位置,開學的時候,老師會給學生每個人分配一個位置,並且不容許學生隨便亂坐位置,之後老師要查看今天李剛同窗有沒有上課,直接看李剛同窗的位置是否是有人就能夠判斷,不必點了全班同窗的名才能夠知道李剛同窗來了沒有。函數
2. 實現簡單的哈希表spa
根據上面的原理,首先,咱們要分配一片空間用來存儲咱們數據,好比是一個空的數組code
而後,有數據存進來的時候,按照特定規則得出這個數據在數組中的位置,將數據存進這個位置blog
咱們就以存進一個整型數據爲例,特定規則就是取餘get
根據計算出來的值,將這些數據放入對應的位置,咱們的數組變爲hash
咱們已經把數據插入到了哈希表中,如今,咱們要查找一個數據,只要按照取餘規則計算出這個數據在數組中對應的位置,而後查看數組的這個位置,就能夠取出這個數據了,好比咱們要從哈希表中取出52,根據取餘規則,52的計算出來的位置是8,數組中8這個位置是空的,52不在哈希表中,找不到52的數據;從哈希表中取出77,77計算出來的位置是0,數組中0這個位置有值,並且值就是77,從哈希表中取出77的值。it
至此,咱們知道實現了一個很簡單的哈希表的原理,其實還存在不少問題,這個咱們接下來討論,這兒先把咱們前面的一些概念用專業的術語替換一下,前面咱們所說的特定規則,咱們稱之爲哈希函數,用特定股則計算出來的值稱之爲哈希值。
3. 還存在哪些問題?
1. 有可能兩個數據經過哈希函數計算出來的哈希值有可能相等,好比77,88計算出來的位置值都是0
2. 若是哈希表滿了,該怎麼擴容
第一個問題就是如何解決這種衝突
有開放定址法,鏈定址法,咱們說一下開放定址法,就是將這個衝突的數據再從新計算一個空的位置,將其存進去,好比咱們要存放88,哈希值是0,數組這個位置已經有值了,那咱們再獲取一個哈希值,好比在原哈希值的基礎上加1,獲得1,1的位置是空,我將88放進去。有人會問,1這個位置被佔了,那下一個數據是1這個位置怎麼辦,這時候,咱們仍是一樣的作法,給這個數據再計算一個哈希值。
插入88後的數組變爲
衝突解決了,但咱們讀取數據的時候,好像又出現問題了,88的哈希值是0,發現數組0位置不是空的,那咱們肯定88在哈希表中?確定不行,0這個位置存儲的是77,不是88。咱們的解決方法是判斷0這個位置的值是否是88,不是的話,再計算88的哈希值是1,判斷是1這個位置是否爲空,爲空,則88不在哈希表中;不爲空,判斷值是否爲88,如果88,肯定在哈希表中;若是值不是88,咱們則繼續計算哈希值是2,依次下去,直到找到88或者值爲空的位置。
第二個問題,哈希表擴容
一個簡單的解決辦法是,當插入數據時,發現全部的位置都滿了,咱們就再分配一個大於原先空間的一片空間,把原來空間中的值從新哈希到新的空間中。
4. 哈希表的python實現
python中的字典就是哈希表,下面代碼實現了一個簡單的字典
class Dict: def __init__(self, size=10): self.size = size self.key = [None] * self.size self.data = [None] * self.size def __setitem__(self, key, value): assert isinstance(key, int) index = self.hash(key) if not self.key[index]: self.key[index] = key self.data[index] = value elif self.key[index] == key: self.data[index] = value else: start = index while self.key[index] and self.key[index] != key: index = self.re_hash(index) if index == start: raise Exception('dict is full') if self.key[index]: self.data[index] = value else: self.key[index] = key self.data[index] = value def __getitem__(self, item): assert isinstance(item, int) index = self.hash(item) if not self.key[index]: raise KeyError(item) else: if self.key[index] == item: return self.data[index] else: start = index while self.key[index] and self.key[index] != item: index = self.re_hash(index) if start == index: raise KeyError(item) if self.key[index] == item: return self.data[index] else: raise KeyError(item) def __contains__(self, item): assert isinstance(item, int) index = self.hash(item) if not self.key[index]: return False else: if self.key[index] == item: return True else: start = index while self.key[index] and self.key[index] != item: index = self.re_hash(index) if start == index: break if self.key[index] == item: return True else: return False def hash(self, key): index = key % self.size return int(index) def re_hash(self, index): return index+1 a = Dict() a[1]='3' a[2]='4' print(a[5])
哈希表對於數據的插入,刪除,更新操做複雜的平均是O(1),效率很是高,若是不關心數據的存儲順序,咱們能夠選取這種數據結構。