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

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)

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

哈希地址0~10

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)

重建哈希表

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

哈希地址0~18

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)

请按任意键继续.. .

*/

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

时间: 2024-10-09 20:34:00

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

8. 蛤蟆的数据结构进阶八哈希表相关概念

8. 蛤蟆的数据结构进阶八哈希表相关概念 本篇名言:"作家当然必须挣钱才能生活,写作,但是他决不应该为了挣钱而生活,写作.--马克思" 前些笔记我们学习了二叉树相关.现在我们来看下哈希表.这篇先来看下哈希表的相关概念 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47347273 1.  哈希表的概念 哈希表(HashTable)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构.它通过把关键

19. 蛤蟆的数据结构进阶十九外部排序相关概念

19. 蛤蟆的数据结构进阶十九外部排序相关概念 本篇名言:"一个人最怕不老实,青年人最可贵的是老实作风. "老实 " 就是不自欺欺人,做到不欺骗人家容易,不欺骗自己最难. "老实作风 " 就是脚踏实地,不占便宜.世界上没有便宜的事,谁想占便宜水就会吃亏. --徐特立" 之前我们学习的排序都是内部排序的,接下去来看下外部排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47

17. 蛤蟆的数据结构进阶十七排序实现之归并排序

17. 蛤蟆的数据结构进阶十七排序实现之归并排序 本篇名言:"人生不是一种享乐 ,而是一桩十分沉重的工作.-- 列夫 . 托尔斯泰" 我们来看下归并排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47790163 1.  归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个

16. 蛤蟆的数据结构进阶十六排序实现之基数排序

16. 蛤蟆的数据结构进阶十六排序实现之基数排序 本篇名言:"社会犹如一条船 ,每人都要有掌舵的准备.--易卜生" 我们来看下基数排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47760601 1.  基数排序 基数排序(radix sort)属于"分配式排序"(distributionsort),又称"桶子法"(bucket sort)或bin sort,顾名思义,

15. 蛤蟆的数据结构进阶十五排序实现之堆排序

15. 蛤蟆的数据结构进阶十五排序实现之堆排序 本篇名言:"谁要是游戏人生 ,他就一事无成 ; 谁不能主宰自己 ,永远是一个奴隶.--歌德" 继续来看下堆排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47733553 1.  堆排序 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.堆分为大根堆和小根堆,是完全二叉树

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序 本篇名言:"即是我们是一支蜡烛也应该 " 蜡烛成灰泪始干 " 即使我们只是一根火柴也要在关键时刻有一次闪耀即使我们死后尸骨都腐烂了解也要变成磷火在荒野中燃烧. -- 艾青" 继续来看什么是简单选择排序. 欢迎转载,转载请标明出处: 1.  简单选择排序 设所排序序列的记录个数为n.i取1,2,-,n-1,从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出排序码最小的记录,与第i个记录交换.执行n-1趟后就完

3. 蛤蟆的数据结构进阶三静态查询之折半查询

3. 蛤蟆的数据结构进阶三静态查询之折半查询 本篇名言:"但是话不行,要紧的是做. --鲁迅" 继续来看静态查询的折半查询. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47211637 1.  折半查找 折半查找要求查找表用顺序存储结构存放且各数据元素按关键字有序(升序或隆序)排列,也就是说折半查找只适用于对有序顺序表进行查找. 折半查找的基本思想是:首先以整个查找表作为查找范围,用查找条件中给定值k与中间位置

18. 蛤蟆的数据结构进阶十八排序实现之快速排序

18. 蛤蟆的数据结构进阶十八排序实现之快速排序 本篇名言:"一个人做点好事并不难,难的是一辈子做好事,不做坏事.--毛泽东" 我们最后来看下快速排序,以及各个排序之间的一些信息汇总. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47817933 1.  快速排序 快速排序由C. A. R.Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分

12. 蛤蟆的数据结构进阶十二排序实现之直接插入法

12. 蛤蟆的数据结构进阶十二排序实现之直接插入法 本篇名言:"路是脚踏出来的 ,历史是人写出来的,人的每一步行动都在书定自己的历史. --吉鸿昌" 接下来看下直接插入法的实现. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47687631 1.  直接插入法 直接插入排序(straightinsertion sort) 每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序. 第一趟比较前两