哈希表又稱散列表,是一種通過鍵值映射到值的數據結構,具有查找快速的優點。
哈希表的基本思想是:
14 |
23 9 |
|
39 25 11 |
|
|
首先我們觀察一下上圖用常規拉鍊法所造出的哈希表,它有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;
}