1. 程式人生 > >雜湊表的構造方法、衝突處理方法及雜湊拉鍊法的簡單程式碼實現

雜湊表的構造方法、衝突處理方法及雜湊拉鍊法的簡單程式碼實現

  由於雜湊表的查詢高效性,在平時的演算法中用的也是比較多。例如:字串、單詞個數的統計,只出現一次字元或者數字的統計,兩個集合相同元素的查詢等等,還有插入刪除的高效(鏈地址法)都可以用雜湊表來解決。所以這裡對其做一個小小的總結。缺點可能是需要佔用額外的記憶體空間。

一、雜湊函式的構造方法 下面介紹五種常用的雜湊構造方法: 構造雜湊函式的原則是: (1)函式本身便於計算; (2)計算出來的地址分佈均勻,即對任一關鍵字k,f(k) 對應不同地址的概率相等,目的是儘可能減少衝突。1、除留餘數法;  取關鍵字被某個不大於雜湊表長m的數p除後所得的餘數為雜湊地址。即:           H(key)=key MODE p,p<=m.(p的取值最好為素數)。  若衝突較多,可取較大的m和p值。2、隨機法;

採用一個偽隨機函式做雜湊函式,即:          H(key)=random(key)。其中random為隨機函式。 通常,當關鍵字長度不等時採用此法構造雜湊函式較為恰當。3、平方取中法; 當無法確定關鍵字中哪幾位分佈較均勻時,可以先求出關鍵字的平方值,然後按需要取平方值的中間幾位作為雜湊地址。 這是因為:平方後中間幾位和關鍵字中每一位都相關,故不同關鍵字會以較高的概率產生不同的雜湊地址。 例如對於關鍵key:123。1234^2=1522756,H(k)關鍵字的雜湊地址為:227.4、摺疊法;       這種方法是按雜湊表地址位數將關鍵字分成位數相等的幾部分(最後一部分可以較短),然後將這幾部分相加,捨棄最高進位後的結果就是該關鍵字的雜湊地址。具體方法有摺疊法與移位法。移位法是將分割後的每部分低位對齊相加,摺疊法是從一端向另一端沿分割界來回摺疊(奇數段為正序,偶數段為倒序),然後將各段相加。 例如:key=12360324711202065,雜湊表長度為1000,則應把關鍵字分成3位一段,在此捨去最低的兩位65,分別進行移位疊加和摺疊疊加,求得雜湊地址為105和907。5、直接定址法;
取關鍵字或關鍵字的某個線性函式值為雜湊地址。即:         H(key)=key  或 H(key)=a*key+b 其中a、b為常數(這種hash函式叫做自身函式)。6、數字分析法;   如果事先知道關鍵字集合,並且每個關鍵字的位數比雜湊表的地址碼位數多時,可以從關鍵字中選出分佈較均勻的若干位,構成雜湊地址。 例如,有1000個記錄,關鍵字為10位十進位制整數d1d2d3…d7d8d9d10,如雜湊表長取1200,則雜湊表的地址空間為:000~1199。假設經過分析,各關鍵字中 d3、d5和d7的取值分佈較均勻,則雜湊函式為:h(key)=h(d1d2d3…d7d8d9d10)=d3d5d7。 例如,h(3748597089)=457,h(9846372561)=432。就是找數字中分佈均勻的數字。二、處理衝突的方法: 1、開放定址法,又稱下標加1法
這種方法也稱再雜湊法,其基本思想是:當關鍵字key的雜湊地址p=H(key)出現衝突時,以p為基礎,產生另一個雜湊地址p1,如果p1仍然衝突,再以p為基礎,產生另一個雜湊地址p2,…,直到找出一個不衝突的雜湊地址pi ,將相應元素存入其中。這種方法有一個通用的再雜湊函式形式:     Hi=(H(key)+di)% m   i=1,2,…,n     其中H(key)為雜湊函式,m 為表長,di稱為增量序列。增量序列的取值方式不同,相應的再雜湊方式也不同。主要有以下三種:   (1)線性探測再雜湊   (2)二次探測再雜湊   (3)偽隨機探測再雜湊     缺點是:線性探測再雜湊容易產生“二次聚集”。當刪除某個資料的時候,需要設定標記或者移動資料,否則會導致查詢的中斷。2、再雜湊法: 這種方法是同時構造多個不同的雜湊函式:    Hi=RH1(key)  i=1,2,…,k 當雜湊地址Hi=RH1(key)發生衝突時,再計算Hi=RH2(key)……,直到衝突不再產生。這種方法不易產生聚集,但增加了計算時間。3、鏈地址法;需要額外的空間;    這種方法的基本思想是將所有雜湊地址為i的元素構成一個稱為同義詞鏈的單鏈表,並將單鏈表的頭指標存在雜湊表的第i個單元中,因而查詢、插入和刪除主要在同義詞鏈中進行。鏈地址法適用於經常進行插入和刪除的情況。4、公共溢位區; 這種方法的基本思想是:將雜湊表分為基本表和溢位表兩部分,凡是和基本表發生衝突的元素,一律填入溢位表三、雜湊表拉鍊法的具體實現  鏈地址法(拉鍊法) 當儲存結構是連結串列時,多采用拉鍊法,用拉鍊法處理衝突的辦法是:把具有相同雜湊地址的關鍵字(同義詞)值放在同一個單鏈表中,稱為同義詞連結串列。有m個雜湊地址就有m個連結串列,同時用指標陣列T[0..m-1]存放各個連結串列的頭指標,凡是雜湊地址為i的記錄都以結點方式插入到以T[i]為指標的單鏈表中。T中各分量的初值應為空指標。 雜湊表拉鍊法查詢的具體實現程式碼:

#include <iostream>
using namespace std;
#define  MODLE 13
struct Haxi_Table
{
    int data;//記錄一共有多少資料
    char a;
    Haxi_Table *next;
};

Haxi_Table *haxi_table[MODLE];//雜湊表陣列;
void Create_Haxi(int arry[],int num)
{
    for(int i=0;i<num;i++)
    {
        int index=arry[i]%MODLE;
        Haxi_Table *temp=new Haxi_Table;
        temp->a=i+97;
        temp->data=num;
        temp->next=NULL; 
        if(!haxi_table[index])
        {
            haxi_table[index]=temp;
        }
        else
        {
            temp->next=haxi_table[index];
            haxi_table[index]=temp;
        }
    }
}
char FindValue(int value)
{
    int index=value%MODLE;
    Haxi_Table *p=haxi_table[index];
    while(p)
    {
        if(p->data=value)
        {
            return p->a;
        }
        else
        {
            p=p->next;
        }
    }
    return -1;
}
void DestoryHash()
{
    Haxi_Table *temp=NULL;
    for(int i=0;i<MODLE;i++)
    {
        if(haxi_table[i])
        {
            while(haxi_table[i])
            {
                temp=haxi_table[i];
                haxi_table[i]=haxi_table[i]->next;
                delete temp;
            }
        }
    }
}
int main()
{
    int num;
    cout<<"please input the number of your data:"<<endl;
    cin>>num;
    int *array=new int[num];
    cout<<"please input the "<<num<<" data:"<<endl;
    for(int i=0;i<num;i++)
        cin>>array[i];
    Create_Haxi(array,num);
    cout<<"查詢結果,8對應的字元為:"<<FindValue(8)<<endl;
    DestoryHash();
    system("pause");
    return 0;
}