1. 程式人生 > >hash表建立,查詢,詳解

hash表建立,查詢,詳解

散列表(Hash table,也叫雜湊表),是根據關鍵字(Key value)而直接訪問在記憶體儲存位置的資料結構。也就是說,它通過計算一個關於鍵值的函式,將所需查詢的資料對映到表中一個位置來訪問記錄,這加快了查詢速度。這個對映函式稱做雜湊函式,存放記錄的陣列稱做散列表。

應用場景

任何一個問題,當選擇資料結構的時候一般只有有限的幾個選擇:陣列、連結串列、二叉樹(絕大多數的場景下都是使用二叉查詢樹或者其變體如平衡二叉樹、紅黑樹等)、雜湊表。二叉樹上的一般操作(查詢、插入、刪除)的最優時間複雜度往往是O(log n),而hash表上的一般操作(查詢、插入、刪除)時間複雜度是O(1)。因此,當某個問題要求時間複雜度是O(1)時,一般只有使用雜湊表這一個唯一的選擇。當然,一個長度為n的雜湊表的空間複雜度是O(n)。

小結:某個場景要求時間複雜度為O(1),考慮雜湊表

In many situations, hash tables turn out to be more efficient than search trees or any other table lookup structure. For this reason, they are widely used in many kinds of computer software, particularly for associative arraysdatabase indexingcaches, and sets

.

雜湊對映

1) 根據key值計算hash值: hash = hashfunc(key)

1

2) 將hash值對映到存放記錄的陣列中:index = hash % array_size

1
2
array_size:存放記錄的陣列的長度
index:記錄在陣列中的下標索引

注:hash是一種對映方式,指的是上面的(1)。hash的使用場景很多,比如加密雜湊,區域性敏感雜湊,而hash table(上述的1,2)只是hash的一個應用場景。

當key是int型別的資料時,可以不用上述第(1)步處理,直接第(2)步計算index,即:

 當key是其他型別的資料時,比如字串,則必須先計算一個hash值才能計算index,即:  A small phone book as a hash table: 

雜湊函式構造

一個性能良好的的雜湊函式 hashfunc(key) 應該具備下面兩個特點:

  1. the function should provide a uniform distribution of hash values
  2. Perfect hashing allows for constant time lookups in the worst case

常見雜湊函式

  • 直接定址法:取關鍵字或關鍵字的某個線性函式值為雜湊地址。即 或 ,其中  為常數(這種雜湊函式叫做自身函式)

  • 數字分析法:假設關鍵字是以r為基的數,並且雜湊表中可能出現的關鍵字都是事先知道的,則可取關鍵字的若干數位組成雜湊地址。

  • 平方取中法:取關鍵字平方後的中間幾位為雜湊地址。通常在選定雜湊函式時不一定能知道關鍵字的全部情況,取其中的哪幾位也不一定合適,而一個數平方後的中間幾位數和數的每一位都相關,由此使隨機分佈的關鍵字得到的雜湊地址也是隨機的。取的位數由表長決定。

  • 摺疊法:將關鍵字分割成位數相同的幾部分(最後一部分的位數可以不同),然後取這幾部分的疊加和(捨去進位)作為雜湊地址。

  • 隨機數法

  • 除留餘數法:取關鍵字被某個不大於散列表表長m的數p除後所得的餘數為雜湊地址。即, 。不僅可以對關鍵字直接取模,也可在摺疊法、平方取中法等運算之後取模。對p的選擇很重要,一般取素數或m,若p選擇不好,容易產生碰撞。

字串雜湊

下面介紹兩種使用最廣泛的效能優良的字串hash值計算方法:DJB Hash,Murmur Hash。Redis的字典實現中就使用了這兩種雜湊演算法。 下面介紹兩種使用最廣泛的效能優良的字串hash值計算方法:DJB Hash,Murmur Hash。Redis的字典實現中就使用了這兩種雜湊演算法。

1. DJB Hash Function

An algorithm produced by Professor Daniel J. Bernstein and shown first to the world on the usenet newsgroup comp.lang.c.It is one of the most efficient hash functions ever published.

1
2
3
4
5
6
7
8
9
unsigned int DJBHash(const std::string& str)
{
   unsigned int hash = 5381;
   for(std::size_t i = 0; i < str.length(); i++)
   {
      hash = ((hash << 5) + hash) + str[i];
   }
   return hash;
}

2.Murmur Hash

MurmurHash 是一種非加密型雜湊函式,適用於一般的雜湊檢索操作。 由Austin Appleby在2008年發明,並出現了多個變種,都已經發布到了公有領域。與其它流行的雜湊函式相比,對於規律性較強的key,MurmurHash的隨機分佈特徵表現更良好。當前的版本是MurmurHash3,能夠產生出32-bit或128-bit雜湊值。具體資訊請參考 MurmurHash 的主頁:http://code.google.com/p/smhasher/ 。

演算法虛擬碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Murmur3_32(key, len, seed)
    // Note: In this version, all integer arithmetic is performed with unsigned 32 bit integers.
    //       In the case of overflow, the result is constrained by the application of modulo  arithmetic.    
    c1  0xcc9e2d51    c2  0x1b873593    r1  15    r2  13    m  5    n  0xe6546b64
    hash  seed
    for each fourByteChunk of key
        k  fourByteChunk
        k  k * c1
        k  (k << r1) OR (k >> (32-r1))
        k  k * c2
        hash  hash XOR k
        hash  (hash << r2) OR (hash >> (32-r2))
        hash  hash * m + n
    with any remainingBytesInKey
        remainingBytes  SwapEndianOrderOf(remainingBytesInKey)