一、哈希表(散列表hash table)定義算法
哈希表就是利用哈希算法(散列技術)將記錄保存到一塊連續的存儲空間中,這塊連續的存儲空間就叫作哈希表或散列表。數據結構
散列技術就是根據記錄的存儲位置和它的關鍵字KEY創建一個肯定的對應關係F,使得每個關鍵字key對應一個存儲位置F(key)。查找時根據這個肯定的對應關係找到給定值key的映射F(key)。函數
這個肯定的對應關係就叫作散列函數,又叫作哈希函數。關鍵字對應的記錄存儲位置叫作散列地址。性能
二、哈希表的查找步驟:搜索引擎
(1)、當存儲時,經過散列函數計算出散列地址,而後按照散列地址將記錄存儲到散列表中。設計
(2)、當查找時,使用與存儲時相同的散列函數計算出散列地址,按次散列地址訪問該記錄。指針
因此散列技術即便一種存儲方法,又是一種查找方法。日誌
三、哈希表與其餘數據結構的區別(如線性表、樹、圖等)?排序
其餘數據結構存儲的數據元素之間存在某種邏輯關係,而哈希表的記錄之間不存在任何邏輯關係,記錄只和關鍵字存在關聯。即一個關鍵字對應一個記錄。哈希表存儲的是鍵值對的形式。索引
哈希表的好處是查找速度快,查找時較其餘數據結構簡化了比較過程,提升了效率。但哈希表不具有不少常規數據結構的能力,如當一個關鍵字對應多個記錄時,不適合用哈希表存儲;同時哈希表也不適合範圍查找,對與對記錄排序、獲取最大值最小值也不能獲得。
散列衝突:當兩個不一樣的關鍵子key1和key2經過散列函數計算獲得相同的散列地址時,這種現象就叫作衝突,引發衝突的關鍵字稱爲散列函數的同義詞。
四、散列函數的構造方法
設計好的散列函數的原則:計算簡單和散列地址分佈均勻。
(1)、直接定址法:即取關鍵字的某個線性函數值做爲散列地址。
散列函數公式:f(key) = a*key + b;(a、b爲常數)
優勢:簡單、均勻、不會產生衝突。
缺點:須要事先直到關鍵字的分佈狀況,適合查找表小且連續的狀況。
(2)、數字分析法:抽取關鍵字的一部分來計算散列地址的方法。
適合處理關鍵字位數比較大的狀況,當事先知道關鍵字的分佈且關鍵字的若干位分佈均勻,這種方法適合。
(3)、平方取中法:取關鍵字平方的中間幾位做爲散列地址。
比較適合事先不知道關鍵字的分佈,而關鍵字位數不是很大的狀況。
(4)、摺疊法:將關鍵字從左到右分紅位數相同的幾部分(最後一部分位數不夠能夠短些),而後將這幾部分疊加求和,再根據哈希表表長,取後幾位做爲散列地址。
摺疊法事先不知道關鍵字的分佈,適合關鍵字位數較多的狀況。
(5)、除留餘數法:此方法是最經常使用的構造散列函數的方法,對於散列表長m的散列函數公式爲:f(key) = key mod p (p<=m)
關鍵就是選擇合適的p值,若表長爲m,一般p爲小於或等於表長(最好接近m)的最大質數或不包含小於20質因子的合數。
(6)、隨機數法:取關鍵字的隨機函數值做爲散列地址。
當關鍵字的長度不等時,採用隨機函數法比較合適。
五、處理散列衝突的方法
設計再好的散列函數也不可能徹底避免衝突的發生,因此要使用其餘的方法來解決衝突。
(1)、開放定址法(閉哈希法):就是一旦發生衝突,就去尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到,並將記錄存入。
開放定址法又分爲三種方法:
線性探測法:散列函數的公式爲f(key) = (f(key) + di) mod m;(di=一、二、三、........m-1)
di爲位移量。線性探測法容易產生堆積現象,就是原來不是同義詞的兩個關鍵字在衝突計算過程當中獲得相同的散列地址。
平方探測法:散列函數的公式爲f(key) = (f(key) + di) mod m;(di=1^二、-1^二、2^二、-2^二、.........p^二、-p^2)(p<=m/2)。
隨機探測法:位移量di採用隨機函數計算獲得。散列函數的公式爲f(key) = (f(key) + di) mod m;(di是一個隨機數列)。
(2)、再散列函數法:對於一個散列表來講,事先準備多個散列函數。每當發生散列衝突時,就換一個散列函數計算散列地址,總會有一個能夠解決衝突。這種方法使得關鍵字不產生彙集,相應的也增長了計算時間。
(3)、鏈地址法(開哈希法):就是將全部關鍵字爲同義詞的記錄存儲到一個單鏈表中,稱次單鏈表爲同義詞子表,在散列表中只存儲同義詞子表的頭指針(散列地址)。優勢是不管有多少衝突,都是在當前位置給單鏈表增長節點的問題;缺點:查找時須要遍歷單鏈表。鏈地址法不會產生任何堆積,於是具備更佳的平均查找性能。
(4)、公共溢出區法:創建一個公共溢出區來存儲全部衝突的關鍵字(同義詞)。
當查找時,經過給定的關鍵字經過散列函數計算出散列地址,先與基本表(散列表)的相應位置進行比較,若是相同,查找成功。不相等,則到溢出表中順序查找。
六、散列表的查找性能
若是散列表沒有發生衝突,散列表的查找性能最高,時間複雜度爲O(1)。可是實際應用中,衝突是不可避免的。
散列表的平均查找長度取決那些因素?
1>、散列函數是否均勻
2>、處理衝突的方法:相同的關鍵字、相同的散列函數,但處理衝突的方法不一樣,則會使平均查找長度不一樣。線性探測法處理衝突可能會產生堆積(就是原來不是同義詞的兩個關鍵字在衝突計算過程當中獲得相同的散列地址),顯然沒有平方探測法性能好,而鏈地址法處理衝突不會產生任何衝突,因此具備更佳的平均查找性能。
3>、散列表的裝填因子:裝填因子a=填入表中的記錄個數/散列表表長。a標誌着散列表的裝滿程度。當填入表中的記錄越多,裝填因子越大,產生衝突的可能性越大。因此:散列表的平均查找長度取決於裝填因子,而不是取決於查找集合的記錄個數。
總結:散列表(哈希表)是一種很是高效的查找數據結構,它與以前數據結構的查找不一樣,它避免了關鍵字之間反覆的比較。而是經過關鍵字直接查找到結果。散列表對於那些查找性能要求高,記錄之間又沒有任何要求的數據有很是好的實用性。
搜索引擎會經過日誌文件把用戶每次檢索使用的全部檢索串都記錄下來,每一個查詢串的長度爲1-255字節。假設目前有一千萬個記錄(這些查詢串的重複度比較高,雖然總數是1千萬,但若是除去重複後,不超過3百萬個。一個查詢串的重複度越高,說明查詢它的用戶越多,也就是越熱門。),請你統計最熱門的10個查詢串,要求使用的內存不能超過1G。
分爲兩個步驟:首先統計query串的次數,而後在找出top10。
統計query串的次數:遍歷全部檢索串,採用hash表存儲,key存儲query串,value存儲query串的次數。時間複雜度爲O(N)。
找出top10:將哈希表建成小頂堆,而後用堆排序找出top10。