9. 数据结构进阶九哈希表实现

9. 数据结构进阶九哈希表实现

“人们所努力追求的庸俗的目标 -- 我总觉得都是可鄙的。 -- 爱因思坦”

上篇我们看了哈希表的相关定义和概念,这篇来看下如何来实现。

1.  代码实现

1.1         Main

函数定义哈希元素数组 10个元素。

定义哈希表变量。

调用InitHashTable构造一个空的哈希表。

然后循环调用函数InsertHash插入记录到哈希表中。如果关键词已经存在则提示该值插入失败。

插入完毕后调用TraverseHash 函数来顺序遍历哈希表。

然后输入待查找的记录关键字,如果找到则输出,没找到则输出没找到。

然后插入第N个记录导致哈希表重建。

最后删除哈希表。

PS:哈希函数是除留余数法。

冲突方法是开放定址法。

1.2         Find

查找关键码为K的元素,查找成功,以p指示待查数据

元素在表中位置,并返回SUCCESS;否则,返回UNSUCCESS

和SearchHash基本一致。

1.3         RecreateHashTable

根据现有的哈希表元素进行分配,数组压缩,然后增大存储容量,

 

1.4         DestroyHashTable

释放分配的哈希表空间。

 

1.5         print

输出元素地址,元素值和元素序号。

 

1.6         TraverseHash

依次输出不会0 的元素。

 

1.7         InitHashTable

输入一个指针。

分配足够量的元素存储空间。

表中数量来自hashsize变量。

设置每个元素的key值为0.

 

1.8         InsertHash

调用searchhash函数寻找是否有相同关键词的元素。

如果有冲突则返回-1退出函数,如果没有冲突则返回可插入的地址。

根据冲突的数量决定是否调用RecreateHashTable函数来重建哈希表。(上限是哈希表元素的一半)

 

1.9         SearchHash

调用Hash函数获得哈希地址。

如果该位置中填有记录.并且关键字不相等,

说明发生了冲突,记录发生冲突的次数。然后调用collision函数进行冲突处理。

如果关键字相等说明找到,直接返回,

如果没找到,则通过输入参数返回可以插入的地址。

 

 

 

1.10     collision(int *p,int d)

进行冲突处理。d表示冲突发生的次数。

处理函数是*p=(*p+d)%m

 

1.11     Hash

哈希函数,通过K%m来获得 地址。

           其中K是元素的值,m是一个全局变量。

 

 

2.  源码

#include<stdio.h>

#include<malloc.h>

#defineNULLKEY 0//0为无记录标志

#defineN10  // 数据元素个数

typedefintKeyType;//设关键字域为整型

typedefstruct

{

           KeyTypekey;

           intord;

}ElemType; //数据元素类型

// 开放定址哈希表的存储结构

int hashsize[]={11,19,29,37}; //哈希表容量递增表,一个合适的素数序列

int m=0; // 哈希表表长,全局变量

typedefstruct

{

           ElemType*elem; // 数据元素存储基址,动态分配数组

           intcount; // 当前数据元素个数

           intsizeindex; // hashsize[sizeindex]为当前容量

}HashTable;

#defineSUCCESS 1

#defineUNSUCCESS 0

#defineDUPLICATE-1

// 构造一个空的哈希表

int InitHashTable(HashTable *H)

           inti;

           (*H).count=0;//当前元素个数为0

           (*H).sizeindex=0;//初始存储容量为hashsize[0]

           m=hashsize[0];

           (*H).elem=(ElemType*)malloc(m*sizeof(ElemType));

           if(!(*H).elem)

                     return0; // 存储分配失败

           for(i=0;i<m;i++)

                     (*H).elem[i].key=NULLKEY; //未填记录的标志

 

           return1;

}

//  销毁哈希表H

void DestroyHashTable(HashTable *H)

{

           free((*H).elem);

           (*H).elem=NULL;

           (*H).count=0;

           (*H).sizeindex=0;

}

// 一个简单的哈希函数(m为表长,全局变量)

unsigned Hash(KeyTypeK)

{

           returnK%m;

}

// 开放定址法处理冲突

void collision(int *p,intd) //线性探测再散列

           *p=(*p+d)%m;

}

// 算法9.17

// 在开放定址哈希表H中查找关键码为K的元素,若查找成功,p指示待查数据

// 元素在表中位置,并返回SUCCESS;否则,p指示插入位置,并返回UNSUCCESS

// c用以计冲突次数,其初值置零,供建表插入时参考。

int SearchHash(HashTableH,KeyTypeK,int *p,int *c)

{

           *p=Hash(K);//求得哈希地址

           while(H.elem[*p].key!=NULLKEY&&!(K== H.elem[*p].key))

           {

                     //该位置中填有记录.并且关键字不相等

                     (*c)++;

                     if(*c<m)

                                collision(p,*c);//求得下一探查地址p

                     else

                                break;

           }

           if (K== H.elem[*p].key)

                     returnSUCCESS; //查找成功,p返回待查数据元素位置

           else

                     returnUNSUCCESS; //查找不成功(H.elem[p].key==NULLKEY)p返回的是插入位置

}

int InsertHash(HashTable*,ElemType); // 对函数的声明

// 重建哈希表

void RecreateHashTable(HashTable *H) //重建哈希表

{

           inti,count=(*H).count;

           ElemType*p,*elem=(ElemType*)malloc(count*sizeof(ElemType));

           p=elem;

           printf("重建哈希表\n");

           for(i=0;i<m;i++)//保存原有的数据到elem

                     if(((*H).elem+i)->key!=NULLKEY) //该单元有数据

                                *p++=*((*H).elem+i);

           (*H).count=0;

           (*H).sizeindex++;//增大存储容量

           m=hashsize[(*H).sizeindex];

           p=(ElemType*)realloc((*H).elem,m*sizeof(ElemType));

           if(!p)

                     return; //存储分配失败

           (*H).elem=p;

           for(i=0;i<m;i++)

                     (*H).elem[i].key=NULLKEY; //未填记录的标志(初始化)

           for(p=elem;p<elem+count;p++)//将原有的数据按照新的表长插入到重建的哈希表中

                     InsertHash(H,*p);

}

// 算法9.18

// 查找不成功时插入数据元素e到开放定址哈希表H中,并返回1

// 若冲突次数过大,则重建哈希表。

int InsertHash(HashTable *H,ElemTypee)

{

           intc,p;

           c=0;

           if(SearchHash(*H,e.key,&p,&c))//表中已有与e有相同关键字的元素

                     returnDUPLICATE;

           elseif(c<hashsize[(*H).sizeindex]/2)//冲突次数c未达到上限,(c的阀值可调)

           {

                     //插入e

                     (*H).elem[p]=e;

                     ++(*H).count;

                     return1;

           }

           else

                     RecreateHashTable(H);//重建哈希表

 

           return0;

}

// 按哈希地址的顺序遍历哈希表

void TraverseHash(HashTableH,void(*Vi)(int,ElemType))

           inti;

           printf("哈希地址0%d\n",m-1);

           for(i=0;i<m;i++)

                     if(H.elem[i].key!=NULLKEY) //有数据

                                Vi(i,H.elem[i]);

}

// 在开放定址哈希表H中查找关键码为K的元素,若查找成功,p指示待查数据

// 元素在表中位置,并返回SUCCESS;否则,返回UNSUCCESS

int Find(HashTableH,KeyTypeK,int *p)

{

           intc=0;

           *p=Hash(K);//求得哈希地址

           while(H.elem[*p].key!=NULLKEY&&!(K== H.elem[*p].key))

           { //该位置中填有记录.并且关键字不相等

                     c++;

                     if(c<m)

                                collision(p,c);//求得下一探查地址p

                     else

                                returnUNSUCCESS; //查找不成功(H.elem[p].key==NULLKEY)

           }

           if (K== H.elem[*p].key)

                     returnSUCCESS; //查找成功,p返回待查数据元素位置

           else

                     returnUNSUCCESS; //查找不成功(H.elem[p].key==NULLKEY)

}

void print(intp,ElemTyper)

{

           printf("address=%d(%d,%d)\n",p,r.key,r.ord);

}

int main()

{

           ElemTyper[N] = {

                     {17,1},{60,2},{29,3},{38,4},{1,5},

                     {2,6},{3,7},{4,8},{60,9},{13,10}

           };

           HashTableh;

           inti, j, p;

           KeyTypek;

 

           InitHashTable(&h);

           for(i=0;i<N-1;i++)

           {

                     //插入前N-1个记录

                     j=InsertHash(&h,r[i]);

                     if(j==DUPLICATE)

                                printf("表中已有关键字为%d的记录,无法再插入记录(%d,%d)\n",

                                r[i].key,r[i].key,r[i].ord);

           }

           printf("按哈希地址的顺序遍历哈希表:\n");

           TraverseHash(h,print);

           printf("请输入待查找记录的关键字: ");

           scanf("%d",&k);

           j=Find(h,k,&p);

           if(j==SUCCESS)

                     print(p,h.elem[p]);

           else

                     printf("没找到\n");

           j=InsertHash(&h,r[i]);//插入第N个记录

           if(j==0)//重建哈希表

                     j=InsertHash(&h,r[i]);//重建哈希表后重新插入第N个记录

           printf("按哈希地址的顺序遍历重建后的哈希表:\n");

           TraverseHash(h,print);

           printf("请输入待查找记录的关键字: ");

           scanf("%d",&k);

           j=Find(h,k,&p);

           if(j==SUCCESS)

                     print(p,h.elem[p]);

           else

                     printf("没找到\n");

           DestroyHashTable(&h);

 

          

           return0;

}

/*

输出效果:

表中已有关键字为60的记录,无法再插入记录(60,9)

按哈希地址的顺序遍历哈希表:

哈希地址010

address=1 (1,5)

address=2 (2,6)

address=3 (3,7)

address=4 (4,8)

address=5 (60,2)

address=6 (17,1)

address=7 (29,3)

address=8 (38,4)

请输入待查找记录的关键字:17

address=6 (17,1)

重建哈希表

按哈希地址的顺序遍历重建后的哈希表:

哈希地址018

address=0 (38,4)

address=1 (1,5)

address=2 (2,6)

address=3 (3,7)

address=4 (4,8)

address=6 (60,2)

address=10 (29,3)

address=13 (13,10)

address=17 (17,1)

请输入待查找记录的关键字:13

address=13 (13,10)

请按任意键继续.. .

*/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值