码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-08 22:54:42      阅读:194      评论:0      收藏:0      [点我收藏+]

标签:

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

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

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

欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47362781


1.  代码实现

1.1             Main

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

定义哈希表变量。

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

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

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

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

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

最后删除哈希表。

运行如下图1

 技术分享

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  // 数据元素个数

typedefint KeyType;//设关键字域为整型

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)

{

         return K%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)

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

         else

                   return UNSUCCESS; //查找不成功(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有相同关键字的元素

                   return DUPLICATE;

         else if(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

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

         }

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

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

         else

                   return UNSUCCESS; //查找不成功(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)

请按任意键继续.. .

*/

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:

原文地址:http://blog.csdn.net/notbaron/article/details/47362781

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!