排序和搜索(三)——hash查找之hash函數(1)

在之前的(一)順序查找和(二)二分查找中我們都是基於數據在列表中存儲的索引位置查找的,本文所要說的是基於hash表的查找

hash表】又名散列表,是一種根據關鍵碼尋找值的數據映射結構。哈希表的每個位置,通常稱爲槽,對應存儲一個項,由0開始,如圖所示是一個size爲10的哈希表,最初每個槽中沒有值,均爲None.

hash函數】又稱爲散列函數,是數據值與哈希表之間的映射函數。哈希函數接收數據值,返回值結餘0和size-1之間的整數(槽名範圍內),在上述哈希表中,返回的哈希值就必須介於0-9之間。下面介紹一下常見的哈希函數:

1)餘數法

將數據值除以表的大小size,所得餘數即爲該數據值對應的槽的位置

H(item)=item%size

將數據25,38,46,12,31按照餘數法插入到上述哈希表中,則有如下

25%10

5

38%10

8

46%10

6

12%10

2

31%10

1

 餘數法存在的問題是,如果輸入數據86,餘數6,和46所在槽衝突。如果要避免衝突就要儘可能提供多點槽,這樣又存在資源利用率不高,因此下面幾種方法就是做到最大程度減少衝突

(2)分組求和法

 將項劃分爲相等大小的塊(最後一塊可能不是相等大小)。然後將這些塊加在一起以求出散列值。例如,如果我們的項是電話號碼 436-555-4601,我們將取出數字,並將它們分成2位數(43,65,55,46,01)43 + 65 + 55 + 46 + 01,我們得到 210。我們假設哈希表有 11 個槽,那麼我們需要除以 11 。在這種情況下,210%11 爲 1,因此電話號碼 436-555-4601 散列到槽 1 。一些分組求和法會在求和之前每隔一個反轉。對於上述示例,我們得到 43 + 56 + 55 + 64 + 01 = 219,其給出 219%11 = 10 

(3)平方取中法

首先求數據值得平方,然後提取一部分數字結果。例如,如果項是 44,我們將首先計算 44^2 = 1,936 。通過提取中間兩個數字 93 ,我們得到 5(93%11)

 (4)利用ascii碼(字符串)

對於字符串,求其散列值可以將字符串理解爲一個字符構成的序列,而每個字符對應一個ascii值,因此字符串也可以理解爲ascii的序列。利於求H('cat'),在ascii碼中,


得出三個字符的ascii值後,相加99+97+116=312,再利用餘數法求出散列值312%10=2,見【代碼1】

值得注意的是,這種基於ascii碼的哈希函數對於字符組成相同的得出的散列值是一樣的,即同樣存在衝突問題,例如利用【代碼1】求出的‘team’和‘meat’相同。

解決方式:可採用字符位置座位權重,例如,cat可採用99*1+97*2+116*3==641,641%10=1,見【代碼2】

【代碼1】

#利用ascii碼(字符串)
def hashSearchByAscii(str,tablesize):
    sum=0
    for s in str:
        sum=sum+ord(s)
    return sum%tablesize
print(hashSearchByAscii('cat',10))

【代碼2】
#利用ascii碼(字符串)+字符的位置權重
def hashSearchByAscii2(str,tablesize):
    sum=0
    for i in range(len(str)):
        sum=sum+ord(str[i])*(i+1)
    return sum%tablesize
print(hashSearchByAscii2('team',10))
print(hashSearchByAscii2('meat',10))
print(hashSearchByAscii2('cat',10))

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章