HashTable的拉鍊法的數組實現

哈希表又稱散列表,是一種通過鍵值映射到值的數據結構,具有查找快速的優點。

哈希表的基本思想是:

1.以結點的關鍵字k爲自變量,通過一個確定的哈希函數H,計算出對應的函數值H(k),作爲結點的存儲位置並將結點存入。
2.順序查找、折半查找、樹的查找是建立在比較基礎上的查找,而哈希表的查找是直接查找
但是對於一個確定的哈希函數H,其對於所需存儲數據計算所得的H(K)可能是相同的,這就是哈希表的衝突,即若某個哈希函數H對於不同的關鍵字得到相同的哈希地址,稱爲衝突


衝突舉例:
比如對於已有關鍵詞序列(14233992511),構造hash函數H爲H(K)=K mod 7,通過hash函數建立含6個元素的hash表,如下:

14

23

9

  

39

25

11

  
  
其中23和9,39和25以及11衝突,應對這種衝突,哈希表有多個處理方法,比如開放定址法,拉鍊法,再哈希法……,這裏介紹的是拉鍊法。


我們先來看看常規的拉鍊法,常規的拉鍊法可以理解爲數組與多個單鏈表的結合,有點類似圖中的鄰接表。它是將所有哈希函數值相同的結點鏈接在同一個單鏈表中。若哈希函數的值域爲0m-1,將散列表定義爲一個由m個頭指針組成的指針數組HT[m],凡是散列地址爲i的結點,均插入到以HT[i]爲頭指針的單鏈表中。
例如給出關鍵詞序列19,14,23,01,68,20,84,27,55,11,10),hash函數爲H(K)=K%13,其構造的拉鍊法hash表如下圖:
其中哈希表的數據只存在其指針數組所引出的單鏈表中。

我要講的哈希表的數組實現也是基於拉鍊法,但是它是不創建單鏈表的,即所有的數據都存在一個數組中,它的思想類似圖的存儲結構中的鏈式前向星,不懂鏈式前向星的可以自行百度,但是對本文沒有閱讀障礙。
首先我們觀察一下上圖用常規拉鍊法所造出的哈希表,它有13個由頭結點組成的數組,以及和關鍵詞序列數目相同的節點,那麼我們不妨創建一個由13個加與關鍵詞序列數目的數組,其中hash節點定義如下:
struct hashNode
{
    int key;//鍵值
    int value;//值
    int postion;//指示位置
};
其中postion用來存放數組下標,然後所定義的數組可以如下:
hashNode hashTable[24];//大小應定爲所插入元素個數的2倍
其中前13個類比哈希表的頭結點數組,後11個存放數據,然後將其全部節點的postion值都定義爲-1,表示其中還沒有存入數據:
memset(hashTable,-1,sizeof (hashTable));//偷了個懶
然後我們構造哈希函數:
int hashf(int key)//hash函數
{
    return key%11;
}
並且我們定義一個輔助變量cnt,將其初始化爲第一個存放數據的數組下標,現在是13;
int cnt=13;
當我們插入數據時我們先計算出它的hash值,比如第一個鍵值19,它的hash值是19%11=8,那麼我們查找哈希表的第8個節點,發現它的postion值爲-1,表明這個hash值還未插入數據,然後我們令這個節點的postion值等於此時的cnt值,再在cnt這個節點中裝入hash節點,再讓cnt++,這就是插入第一個未查找過的hash值的方法。那麼如果這個hash值不是第一次被訪問,比如我再插入一個關鍵詞爲8的哈希節點,那麼我們可以通過一個while循環,找到第一個表中節點postion值不爲-1的點,再重複插入操作,其代碼如下,其中hashlen值是構造hash函數用的:
void hash_insert(int key,int value,int hashlen,int &cnt)
{
    int pos=hashf(key,hashlen);
    while (hashTable[pos].postion!=-1)//當pos位上的hash表已經存儲了位置時,找到沒有存儲位置的hash表
    {
        pos=hashTable[pos].postion;
    }
    hashTable[pos].postion=cnt;
    hashTable[cnt].key=key;//cnt爲用於存儲hash節點最近的空節點的下標
    hashTable[cnt].value=value;
    cnt++;
}
那麼我們現在構建好了哈希表,下一步就是根據鍵值查找hash元素,我們可以先通過算出hash函數,然後對其節點開始遍歷,當該節點還有下一個指向的節點時,不斷的進行循環,除非該節點就是我們所需尋找的節點,其中有一個注意點,那就是頭結點的那個節點不應拿來比較鍵值是否相等,代碼如下:
int hash_search(int key,int hashlen)
{
    int pos=hashf(key,hashlen);
    while (hashTable[pos].postion!=-1)//pos>=hashlen是因爲hash表的前len個節點只存放位置,不存放數據
    {
        if (key==hashTable[pos].key&&pos>=hashlen)
            return hashTable[pos].value;
        else
            pos=hashTable[pos].postion;
    }
    if (key==hashTable[pos].key&&pos>=hashlen)
        return hashTable[pos].value;

    printf("無法找到\n");
    return 0x3f3f3f3f;
}
至於哈希節點的刪除,這件事就交給機智的你來完成了……
總的代碼:
//類似於hash表的拉鍊法實現
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

struct hashNode
{
    int key;//鍵值
    int value;//值
    int postion;//指示位置
};

hashNode hashTable[1000];//大小爲hashlen的2倍即可

int hashf(int key,int hashlen)//hash函數
{
    return key%hashlen;
}

void hash_insert(int key,int value,int hashlen,int &cnt)
{
    int pos=hashf(key,hashlen);
    while (hashTable[pos].postion!=-1)//當pos位上的hash表已經存儲了位置時,找到沒有存儲位置的hash表
    {
        pos=hashTable[pos].postion;
    }
    hashTable[pos].postion=cnt;
    hashTable[cnt].key=key;//cnt爲用於存儲hash節點最近的空節點的下標
    hashTable[cnt].value=value;
    cnt++;
}

int hash_search(int key,int hashlen)
{
    int pos=hashf(key,hashlen);
    while (hashTable[pos].postion!=-1)//pos>=hashlen是因爲hash表的前len個節點只存放位置,不存放數據
    {
        if (key==hashTable[pos].key&&pos>=hashlen)
            return hashTable[pos].value;
        else
            pos=hashTable[pos].postion;
    }
    if (key==hashTable[pos].key&&pos>=hashlen)
        return hashTable[pos].value;

    printf("無法找到\n");
    return 0x3f3f3f3f;
}


int main()
{

    memset(hashTable,-1,sizeof (hashTable));

    int hashlen=10,cnt=hashlen;//hashlen大小爲所需插入元素個數
    int key[10]= {2,3,1,4,13,21,31,10,11,19};
    int value[10]= {4,2,6,10,37,72,17,3,92,11};

    for (int i=0;i<=9;i++)
    {
        hash_insert(key[i],value[i],hashlen,cnt);//cnt與鏈式前向星的思路有點類似
    }

    for (int i=9;i>=0;i--)
    {
        int temp=hash_search(key[i],hashlen);
        printf("%d ",temp);
    }

    return 0;
}









 

 

 

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