1. 程式人生 > 實用技巧 >雜湊表的運算演算法

雜湊表的運算演算法

一、開放定址法構造的雜湊表的運算演算法

1、雜湊表型別

#define NULLKEY-1 //定義空關鍵字
#define DELKEY-2 //定義被刪關鍵字
typedef int KeyType; //關鍵字型別
typedef struct
{
    KeyType key; //關鍵字域
    int count; //探測次數域
}HashTable;

2、插入建表演算法

void InsertHT(HashTable ha[],int &n,int m,int p,KeyType k)
{
    int i,adr;
    adr=k%p; //計算雜湊函式值
    if(ha[adr].key==NULLKEY||ha[adr].key==DELKEY)
    {
        ha[adr].key=k; //k可以直接放在雜湊表中
        ha[adr].count=1;
    }
    else //發生衝突,用線性探測法解決衝突
    {
        i=1; //i記錄k發生衝突的次數
        do
        {
            ard=(ard+1)%m; //線性探測
            i++;
        }while(ha[adr].key!=NULLKEY&&ha[adr].key!=DELKEY);
        ha[adr].key=k; //在adr處放置k
        ha[adr].count=i; //設定探測次數
    }
    n++; //雜湊表中總元素個數增1
}

void CreateHT(HashTable ha[],int &n,int m,int p,KeyType keys[],int nl)
{
    for(int i=0;i<m;i++)
    {
        ha[i].key=NULLKEY;
        ha[i].count=0;
    }
    n=0; //雜湊表中總元素個數從0開始遞增
    for(i=0;i<nl;i++)
    {
        InsertHT(ha,n,m,p,keys[i]); //插入n個關鍵字
    }
}

3、刪除演算法

bool DeleteHT(HashTable ha[],int &n,int m,int p,KeyType k)
{
    int adr;
    adr=k%p; //計算雜湊函式值
    while(ha[adr].key!=NULLKEY&&ha[adr].key!=k)
    {
        adr=(adr+1)%m; //線性探測
    }
    if(ha[adr].key==k) //查詢成功
    {
        ha[adr].key=DELKEY; //刪除k
        return true;
    }
    else
        return fales;
}

4、查詢演算法

void SearchHT(HashTable ha[],int m,int p,KeyType k)
{
    int i=1,adr;
    adr=k%p;
    while(ha[adr].key!=NULLKEY&&ha[adr].key!=k)
    {
        i++; //累計關鍵字比較次數
        adr=(adr+1)%m; //線性探測
    }
    if(ha[ard].key==k) //查詢成功
    {
        printf("成功:關鍵字%d,比較%d次\n",k,i);
    }
    else
    {
        printf("失敗:關鍵字%d,比較%d次\n",k,i);
    }
}

5、線性探測計算成功和不成功平均查詢長度

對於查詢不成功的理解:

根據雜湊函式地址為mod7,因此任何一個數經雜湊函式計算以後的初始地址只可能在0~6的位置

查詢0~6位置查詢失敗的查詢次數為:

地址0,到第一個關鍵字為空的地址2需要比較3次,因此查詢不成功的次數為3

地址1,到第一個關鍵字為空的地址2需要比較2次,因此查詢不成功的次數為2

地址2,到第一個關鍵字為空的地址2需要比較1次,因此查詢不成功的次數為1

地址3,到第一個關鍵字為空的地址4需要比較2次,因此查詢不成功的次數為2

地址4,到第一個關鍵字為空的地址4需要比較1次,因此查詢不成功的次數為1

地址5,到第一個關鍵字為空的地址2(比較到地址6,再迴圈回去)需要比較5次,因此查詢不成功的次數為5

地址6,到第一個關鍵字為空的地址2(比較到地址6,再迴圈回去)需要比較4次,因此查詢不成功的次數為4

二、拉鍊法構造的雜湊表的運算

1、雜湊表型別

typedef int KeyType; //關鍵字型別
typedef struct node
{
    KeyType key; //關鍵字域
    struct node *next; //下一個結點指標
}NodeType;
typedef struct
{
    NodeType *firstp; //首節點指標
}HashTable;

2、插入建表演算法

void InsertHT(HashTable ha[],int &n,int p,KeyType k)
{
    int adr;
    adr=k%p; //計算雜湊函式值
    NodeType *q;
    q=(NodeType *)malloc(sizeof(NodeType));
    q->key=k; //建立結點q,存放k
    q->next=NULL;
    if(ha[adr].firstp==NULL) //若單鏈表adr為空
    {
        ha[adr].firstp=q;
    }
    else
    {
        q->next=ha[adr].firstp; //頭插法
        ha[adr].firstp=q;
    }
    n++; //雜湊表中結點總個數增1
}

void CreateHT(HashTable ha[],int &n,int m,int p,KeyType keys[],int nl)
{
    for(int i=0;i<m;i++) //置初值
    {
        ha[i].firstp=NULL;
    }
    n=0;
    for(i=0;i<nl;i++)
    {
        InsertHT(ha,n,p,keys[i]); //插入n個關鍵字
    }
}

3、刪除演算法

bool DeleteHT(HashTable ha[],int &n,int m,int p,KeyType k)
{
    int adr;
    adr=k%p; //計算雜湊函式值
    NodeType *q,*preq;
    q=ha[adr].firstp; //q指向首節點
    if(q==NULL)
        return false;
    if(q->key==k) //首節點為k
    {
        ha[adr].firstp=q->next; //刪除結點q
        free(q);
        n--;
        return true;
    }
    preq=q; q=q->next; //首節點不為k
    while(q!=NULL)
    {
        if(q->key==k) //查詢成功
            break; //退出迴圈
        q=q->next;
    }
    if(q!=NULL) //查詢成功
    {
        preq->next=q->next; //刪除結點q
        free(q);
        n--; //結點總數減1
        return true;
    }
    else
        return false;
}

4、查詢演算法

void SearchHT(HashTable ha[],int m,int p,KeyType k)
{
    int i=1,adr;
    adr=k%p;
    NodeType *q;
    q=ha[adr].firstp; //q指向對應單鏈表的首節點
    while(q!=NULL) //掃描adr單鏈表所有結點
    {
        i++;
        if(q->key==k) //查詢成功
            break;
        q=q->next;
    }
    if(q!=NULL)
    {
       printf("成功:關鍵字%d,比較%d次\n",k,i); 
    }
    else
    {
        printf("失敗:關鍵字%d,比較%d次\n",k,i);
    }
}