搜索算法—哈希表

 

1.什麼是哈希表(Hash Tables)

  哈希表能夠以極快的速度來查找、添加或刪除元素(只須要數次的比較操做。)它比紅黑樹、二叉搜索樹都要快得多。可是哈希表沒有排序功能,相似的,如尋找最大值、最小值、中值這些行爲都不能在哈希表中實現。數組

 

2.實現哈希表的前提條件

  要想對一組元素作成哈希表形式的數據結構,這些元素須要知足兩個條件:數據結構

  A. 元素擁有本身的哈希值。函數

  B. 兩個元素能夠判斷出是否相等。指針

  第二個條件比較容易實現,關鍵是第一個條件。在介紹哈希表前,將先介紹哈希值。code

 

3. 什麼是哈希值(hash code)

  哈希值是一個int類型的整數。每一個元素都應該有本身的哈希值,而且這個值是惟一的。即知足:blog

  A. 若是元素a與元素b相等,則元素a的哈希值與元素b的哈希值相等。排序

  B. 若是元素a與元素b不相等,則元素a的哈希值與元素b的哈希值不相等。內存

  一般狀況下,對於int,bool,double,string等語言自帶的類型都有本身的哈希值,能夠用它們的哈希函數來獲取,不一樣語言的哈希函數可能會不一樣。string

  若是是用戶本身新建的類型,則須要提供計算此類型元素哈希值的哈希函數。hash

  在哈希表中,咱們是經過某元素的哈希值來查找、添加或刪除元素的。

 

4. 如何實現哈希表

  有許多方法能夠實現哈希表,這裏將介紹兩種:拉鍊法(separate chaining)和線性探測法(linear probing)。

 

5. 拉鍊法(separate chaining)

  從例子入手:

  現有整數類型(int)的數組S:7,30,10,9,14,19,15,12,90,94,93,53,70。此數組的元素的哈希值與元素值相同,即7的哈希值是7;30的哈希值是30。

  現建立一個有5個元素的數組A:(紅色顏色只是爲了與數組S的元素區分開來)

  

  而後按順序把數組S插入數組A中:

  插入元素7:元素7的哈希值爲7,7%5=2,所以插入到2號元素中;

  插入元素30:元素30的哈希值爲30,30%5=0,所以插入到0號元素中;

 

  插入元素10:元素10的哈希值爲10,10%5=0,所以插入到0號元素中,但0號元素已經有數值30了,故插到30後面,元素30的指針指向元素10。

 

  如此類推,插入元素9:元素9的哈希值爲9,9%5=4,所以插入到4號元素中...

  所有元素添加完畢後:

  如今,若是咱們要查找元素19:

  元素19的哈希值爲19,19%5=4,所以到4號元素去找;

  4號元素的值爲9,9!=19,去找9的指針指向的元素14;

  14!=19,去找14的指針指向的元素19;

  19==19,返回數值,查找完畢。

  此過程只經歷了3次比較!

  今後例子中能夠看出思路:

  對於一個擁有N項元素的數組S,咱們須要創建一個含有M項元素的新數組A。

  M的值能夠本身來定,但若是M過大,則會出現不少空鏈,如上述例子中的1號鏈;

  若是M太小,則會出現鏈太長的狀況,若是鏈太長,則意味着比較次數變多。

  通常建議M=N/5。

  插入元素:

  int j=S[i]的哈希值%5;

  而後檢查A[j]是否爲空,若是空,A[j]=S[i]; 若是不爲空,temp=A[j], A[j]=S[i], S[i].next=temp;

  刪除元素:先找出該元素,而後此元素的上一個元素的指針指向此元素的下一個元素,最後刪除此元素。

  拉鍊法有一個缺陷,就是很容易有些鏈過長,有些鏈太短,甚至是空鏈。這樣會浪費內存和影響搜索速度。

 

6. 線性探測法(linear probing)

  從例子入手:

  現有整數類型(int)的數組S:7,30,10,9,14,19,15,29,13,27。此數組的元素的哈希值與元素值相同,即7的哈希值是7;30的哈希值是30。

  現建立一個含有14個元素的數組A:(上面那排數字是爲了方便看哪一個元素是第幾項元素)

  

  而後按順序把數組S插入數組A中:

  插入元素7:元素7的哈希值爲7,7%14=7,所以插入到7號元素中;

  插入元素30:元素30的哈希值爲30,30%14=2,所以插入到2號元素中;

  插入元素10:元素10的哈希值爲10,10%14=10,所以插入到10號元素中;

  插入元素9:元素9的哈希值爲9,9%14=9,所以插入到9號元素中;

  插入元素14:元素14的哈希值爲14,14%14=0,所以插入到0號元素中;

  插入元素19:元素19的哈希值爲19,19%14=5,所以插入到5號元素中;

  插入元素15:元素15的哈希值爲15,15%14=1,所以插入到1號元素中;

  

  插入元素29:元素29的哈希值爲29,29%14=1,但1號元素已經有數值15了,而後檢查下一個元素(2號元素),但2號元素已經有數值30了,而後檢查下一個元素(3號元素),3號元素爲空,插入到3號元素:

  

  插入元素13:元素13的哈希值爲13,13%14=13,所以插入到13號元素中:

  

  插入元素27:元素27的哈希值爲27,27%14=13,但13號元素已經有數值13了,而後檢查下一個元素(0號元素),但0號元素已經有數值14了,如此類推,找到4號元素爲空,插入到4號元素:

  

  若是咱們要查找元素29,元素29的哈希值爲29,29%14=1,檢查1號元素,15!=29;而後檢查下一個元素(2號元素),30!=29;而後檢查下一個元素(3號元素),29=29,返回數值,查找完畢。

  今後例子中能夠看出思路:

  對於一個擁有N項元素的數組S,咱們須要創建一個含有M項元素的新數組A。

   M必定要比N大。若是M過少,則搜索進行的比較次數增長,影響速度;若是過大,則太多空位沒利用,形成內存浪費。

  通常建議M=2*N。

  插入元素i: 先獲取i的哈希值%M,根據這個值插入到相應的位置中,若是位置有元素了,則插入到下一個位置,循環進行,直到位置是空的爲止。

  搜索元素:相似於插入元素,詳細見上述例子。

相關文章
相關標籤/搜索