数据结构哈希表设计
哈希表的定义和工作原理
哈希表的定义和工作原理
哈希表(Hash Table),又称作散列表或哈希映射,是一种用
于存储键值对的数据结构。
它通过哈希函数将键映射到存储位置,从而快速定位到对应的值。
哈希表的工作原理如下:
1. 创建一个固定大小的数组(哈希表),数组的每个元素都是一个链表的头指针。
2. 当插入一个键值对时,将键通过哈希函数计算得到一个哈希值,然后将该键值对存储在哈希值对应的链表中。
3. 当需要查找某个键对应的值时,先将键通过哈希函数计算得到哈希值,然后在哈希值对应的链表中找到该键对应的值。
4. 如果多个键通过哈希函数计算得到的哈希值相同,即出现哈希冲突,则在链表中进行线性搜索或使用其他解决冲突的方法。
哈希表的特点包括:
- 查找、插入和删除操作的平均时间复杂度为O(1),在某些情
况下可以达到O(1)。
- 哈希表的性能依赖于哈希函数的选择和哈希表的负载因子。
- 负载因子表示哈希表中元素的个数与哈希表大小的比值,负
载因子越高,哈希冲突的可能性越高,性能下降。
需要注意的是,哈希函数的设计很重要,好的哈希函数应该尽可能地使得键的哈希值均匀分布,减少哈希冲突的可能性。
常见的哈希函数包括取余法、乘法散列法、折叠法等。
另外,为了解决哈希冲突,常用的方法包括拉链法、开放定址法等。
Python中的哈希表
Python中的哈希表哈希表是一种基本的数据结构,是在计算机科学中被广泛使用的一种算法,也被称为散列表。
在计算机程序中,哈希表是一种根据关键字直接访问数据的数据结构。
哈希表的设计基于哈希函数,它将输入数据转换成一串数字,这个数字就可以唯一地对应输入数据在哈希表中的位置,可以实现非常快速的查找、插入和删除操作。
哈希表主要的优点是它提供了常数级别的时间复杂度,所以它将从大量数据中搜索或枚举出特定条目的工作转变为了对一组异构数据的随机访问,这使得哈希表在计算机工程的许多领域都有广泛的应用。
例如,哈希表在数据库系统、索引系统、网络协议、编译器等各种领域中都得到了广泛的应用。
哈希表的实现通常使用哈希函数将关键字映射到哈希表中的位置,这个位置称为“哈希值”或“索引”,然后将数据存储在这个位置上。
哈希函数从关键字中计算出哈希值(或索引),所以当使用哈希表时需要选择适当的哈希函数,以确保最小化哈希冲突(即两个不同的关键字映射到同一个哈希值上)的概率。
哈希表的核心思想是将大量数据映射到更小的区域(通常是哈希表中的特定位置)中,以便于对它们进行查询、浏览、修改和删除。
具体来说,哈希表的构建要求程序员找到一个适当的哈希函数。
最好的哈希函数往往具有以下几个特性:(1)哈希函数应该足够简单,可以快速、有效地计算出哈希值。
(2)哈希函数应该是确定的,即对于特定的关键字,哈希函数应该始终返回相同的哈希值。
(3)哈希函数应该将不同的关键字分散到哈希表的各个位置,以确保最小化哈希冲突的概率。
(4)哈希函数应该尽可能均匀地将关键字分布在哈希表的不同位置上,从而避免过多的哈希冲突,保证哈希表的性能。
哈希表可以通过不同的底层数据结构来实现,通常使用数组配合链表或红黑树来实现,具体实现细节要根据实际应用场景来考虑。
在一些应用场景中,例如在大量数据的情况下,链式哈希表的效率会大幅下降,此时更适合使用基于红黑树的哈希表或线性哈希表。
另外,哈希表的实现需要考虑压缩问题,即当哈希表中的数据存储超过一定数量后,如何迅速地扩充存储区域,并保证数据的存储连续性和不变性。
c 语言 哈希表
C语言中的哈希表是一种数据结构,用于实现键-值对的存储和检索。
它通过将键映射到数组中的索引来实现高效的查找操作。
在C语言中,哈希表通常使用数组和链表的组合来实现。
一般情况下,哈希表包含一个固定大小的数组,每个数组元素称为一个桶(bucket)。
哈希函数将键映射到数组索引,每个键的哈希函数计算结果都应该是唯一的。
当需要插入一个键值对时,首先通过哈希函数计算键的哈希值,然后将键值对插入到对应索引的桶中。
如果多个键映射到相同的索引,这种情况称为哈希冲突。
为了解决冲突,每个桶通常是一个链表,新的键值对会被插入到链表的头部。
当需要查找一个键时,通过哈希函数计算键的哈希值,然后查找对应索引的桶。
在桶的链表中逐个比较键,直到找到对应的值或者链表结束。
需要注意的是,在哈希表中,哈希函数的设计非常重要,它应该尽可能均匀地将键分布到数组索引中,以减少哈希冲突的概率。
此外,当哈希表的负载因子过高时,即桶中键值对的数量过多,可能会导致性能下降,因此可能需要进行动态调整,例如重新分配更大的数组并重新插入所有键值对。
C语言中可以使用自定义的结构体来表示哈希表,包含数组和链表等成员变量。
操作哈希表的函数可以实现插入、查找、删除等操作,通过调用这些函数来使用哈希表。
总之,哈希表是一种在C语言中实现键-值对存储和检索的数据结构,通过哈希函数将键映射到数组索引,通过数组和链表的组合解决哈希冲突。
哈希表 哈希函数
哈希表哈希函数哈希表是一种常见的数据结构,它通过哈希函数将键映射到存储位置,实现高效的数据查找和插入操作。
本文将从哈希函数的定义、设计原则、应用场景等方面进行介绍和探讨。
一、哈希函数的定义哈希函数是将任意长度的输入映射为固定长度输出的函数。
它的设计目标是将输入的数据分散到哈希表的不同槽位中,尽量避免冲突,使得数据能够均匀地分布在哈希表中。
二、哈希函数的设计原则1. 均匀性:好的哈希函数应该将输入的数据均匀地映射到哈希表的不同槽位中,避免冲突的发生。
常用的哈希函数有除留余数法、平方取中法等。
2. 确定性:同一个输入应该得到相同的输出,这样才能实现数据的查找和插入操作。
3. 高效性:哈希函数的计算速度应该尽可能快,以提高整体的性能。
三、哈希函数的应用场景1. 字典存储:哈希表可以用于实现字典存储结构,将键值对按照键的哈希值存储在哈希表中。
这样可以通过键快速地查找对应的值。
2. 缓存管理:哈希表可以用于实现缓存管理,将数据的哈希值作为索引,将数据存储在哈希表中。
这样可以加快数据的读取速度。
3. 唯一标识:哈希函数可以将数据转化为唯一的标识,用于数据的比较和去重。
例如,在分布式系统中,可以使用哈希函数将数据分配到不同的节点上。
四、哈希函数的性能评估1. 冲突率:冲突率是指哈希函数产生冲突的概率。
冲突率越低,哈希表的性能越好。
2. 均匀性:好的哈希函数应该将数据均匀地映射到哈希表的不同槽位中,避免槽位的过度拥挤。
3. 计算速度:哈希函数的计算速度应该尽可能快,以提高整体的性能。
五、哈希函数的优化策略1. 良好的分布性:选择合适的哈希函数,使得输入数据在哈希表中均匀分布,避免冲突的发生。
2. 良好的计算性能:选择计算速度较快的哈希函数,减少计算的时间消耗。
3. 避免冲突:可以通过增加哈希表的大小或者使用链表等方法来解决冲突的问题。
六、哈希函数的局限性1. 冲突:由于哈希函数的输出是有限的,而输入的数据是无限的,所以冲突是无法完全避免的。
哈希表数据结构例题
哈希表数据结构例题哈希表(HashTables)是一种用于存储数据的结构,它根据键(key)计算出一个值(value),从而将数据存储到对应的位置上。
它是一种用空间换取时间的算法,通过哈希函数将键值转化为整数,并将其映射到一个“桶”中,快速定位查找所需的数据,从而大大减少搜索时间。
哈希表也常用于排序、缓存、验证数据的完整性等方面。
哈希表的原理哈希表的主要原理就是使用一种称为哈希函数(hash function)的算法来将键值转化为整数,然后将其映射到一个“桶”中,也就是一个包含要存储的值的有序数组。
哈希函数是把任意字符串或其他数据类型,转换为一个固定长度的整数,也就是所谓的“哈希值”。
这个哈希值可以根据“哈希函数”的设计,映射到0到桶的大小减一之间的某一个整数。
这样,哈希表就可以把原来的数据,通过哈希值转换为一个范围较小的数,把数据存储到一个有序的桶中,从而大大缩短搜索时间。
哈希表的实现哈希表是使用数组和链表实现的。
数组存放键值对,链表可以解决键值重复的情况,其中每个节点存放着该键值对应的值。
为了更有效的利用存储空间,哈希表有时会采取扩容的方式,即把原来的数组容量翻倍,当存储满的时候就重新分配内存空间,并把原来的数据重新哈希映射到新的桶中。
哈希表的用途哈希表除了作为存储数据的结构,也可以用于排序、缓存、验证数据的完整性等问题。
哈希表常被用来实现快速查找和插入功能,而且它的查找时间复杂度主要取决于所使用的哈希函数,一般在O(1)时间内就可以完成查找。
哈希表也可以快速统计某一个键出现的次数,实现计数排序(Counting Sort)等功能。
哈希表的例题例子1:设计一个哈希表,能够把一个字符串(String)转换为一个哈希值,并且能够用这个哈希值搜索相应的字符串。
解题思路:首先,需要设计一种哈希函数,把一个任意长度的字符串,转换为一个固定长度的哈希值,这里可以采用把字符串中每个字符的ASCII码值相加,再除以字符串长度,取余数的方法。
数据结构课程设计--哈希表实验报告
福建工程学院课程设计课程:算法与数据结构题目:哈希表专业:网络工程班级:xxxxxx班座号:xxxxxxxxxxxx姓名:xxxxxxx2011年12 月31 日实验题目:哈希表一、要解决的问题针对同班同学信息设计一个通讯录,学生信息有姓名,学号,电话号码等。
以学生姓名为关键字设计哈希表,并完成相应的建表和查表程序。
基本要求:姓名以汉语拼音形式,待填入哈希表的人名约30个,自行设计哈希函数,用线性探测再散列法或链地址法处理冲突;在查找的过程中给出比较的次数。
完成按姓名查询的操作。
运行的环境:Microsoft Visual C++ 6.0二、算法基本思想描述设计一个哈希表(哈希表内的元素为自定义的结构体)用来存放待填入的30个人名,人名为中国姓名的汉语拼音形式,用除留余数法构造哈希函数,用线性探查法解决哈希冲突。
建立哈希表并且将其显示出来。
通过要查找的关键字用哈希函数计算出相应的地址来查找人名。
通过循环语句调用数组中保存的数据来显示哈希表。
三、设计1、数据结构的设计和说明(1)结构体的定义typedef struct //记录{NA name;NA xuehao;NA tel;}Record;录入信息结构体的定义,包含姓名,学号,电话号码。
typedef struct //哈希表{Record *elem[HASHSIZE]; //数据元素存储基址int count; //当前数据元素个数int size; //当前容量}HashTable;哈希表元素的定义,包含数据元素存储基址、数据元素个数、当前容量。
2、关键算法的设计(1)姓名的折叠处理long fold(NA s) //人名的折叠处理{char *p;long sum=0;NA ss;strcpy(ss,s); //复制字符串,不改变原字符串的大小写strupr(ss); //将字符串ss转换为大写形式p=ss;while(*p!='\0')sum+=*p++;printf("\nsum====================%d",sum);return sum;}(2)建立哈希表1、用除留余数法构建哈希函数2、用线性探测再散列法处理冲突int Hash1(NA str) //哈希函数{long n;int m;n=fold(str); //先将用户名进行折叠处理m=n%HASHSIZE; //折叠处理后的数,用除留余数法构造哈希函数return m; //并返回模值}Status collision(int p,int c) //冲突处理函数,采用二次探测再散列法解决冲突{int i,q;i=c/2+1;while(i<HASHSIZE){if(c%2==0){c++;q=(p+i*i)%HASHSIZE;if(q>=0) return q;else i=c/2+1;}else{q=(p-i*i)%HASHSIZE;c++;if(q>=0) return q;else i=c/2+1;}}return UNSUCCESS;}void benGetTime();}else printf("\n此人不存在,查找不成功!\n");benGetTime();}(4)显示哈希表void ShowInformation(Record* a) //显示输入的用户信息{int i;system("cls");for( i=0;i<NUM_BER;i++)printf("\n第%d个用户信息:\n 姓名:%s\n 学号:%s\n 电话号码:%s\n",i+1,a[i].name,a[i].xuehao,a[i].tel);}(5)主函数的设计void main(int argc, char* argv[]){Record a[MAXSIZE];int c,flag=1,i=0;HashTable *H;H=(HashTable*)malloc(LEN);for(i=0;i<HASHSIZE;i++){H->elem[i]=NULL;H->size=HASHSIZE;H->count=0;}while (1){ int num;printf("\n ");printf("\n 欢迎使用同学通讯录录入查找系统");printf("\n 哈希表的设计与实现");printf("\n 【1】. 添加用户信息");printf("\n 【2】. 读取所有用户信息");printf("\n 【3】. 以姓名建立哈希表(再哈希法解决冲突) ");printf("\n 【4】. 以电话号码建立哈希表(再哈希法解决冲突) ");printf("\n 【5】. 查找并显示给定用户名的记录");printf("\n 【6】. 查找并显示给定电话号码的记录");printf("\n 【7】. 清屏");printf("\n 【8】. 保存");printf("\n 【9】. 退出程序");printf("\n 温馨提示:");printf("\n Ⅰ.进行5操作前请先输出3 ");printf("\n Ⅱ.进行6操作前请先输出4 ");printf("\n");printf("请输入一个任务选项>>>");printf("\n");scanf("%d",&num);switch(num){case 1:getin(a);break;case 2:ShowInformation(a);break;case 3:CreateHash1(H,a); /* 以姓名建立哈希表*/break;case 4:CreateHash2(H,a); /* 以电话号码建立哈希表*/break;case 5:c=0;SearchHash1(H,c);break;case 6:c=0;SearchHash2(H,c);break;case 7:Cls(a);break;case 8:Save();break;case 9:return 0;break;default:printf("你输错了,请重新输入!");printf("\n");}}system("pause");return 0;3、模块结构图及各模块的功能:四、源程序清单:#include<stdio.h>#include<stdlib.h>#include<string.h>#include <windows.h>#define MAXSIZE 20 #define MAX_SIZE 20 #define HASHSIZE 53 #define SUCCESS 1#define UNSUCCESS -1#define LEN sizeof(HashTable)typedef int Status;typedef char NA[MAX_SIZE];typedef struct {NA name;NA xuehao;NA tel;}Record;typedef struct {Record *elem[HASHSIZE]; int count; int size; }HashTable;Status eq(NA x,NA y) {if(strcmp(x,y)==0)return SUCCESS;else return UNSUCCESS;}Status NUM_BER;void getin(Record* a) {int i;system("cls");printf("输入要添加的个数:\n");scanf("%d",&NUM_BER);for(i=0;i<NUM_BER;i++){printf("请输入第%d个记录的姓名:\n",i+1);scanf("%s",a[i].name);printf("请输入%d个记录的学号:\n",i+1);scanf("%s",a[i].xuehao);printf("请输入第%d个记录的电话号码:\n",i+1);scanf("%s",a[i].tel);}}void ShowInformation(Record* a){int i;system("cls");for( i=0;i<NUM_BER;i++)printf("\n第%d个用户信息:\n 姓名:%s\n 学号:%s\n 电话号码:%s\n",i+1,a[i].name,a[i].xuehao,a[i].tel);}void Cls(Record* a){printf("*");system("cls");}long fold(NA s){char *p;long sum=0;NA ss;strcpy(ss,s);strupr(ss);p=ss;while(*p!='\0')sum+=*p++;printf("\nsum====================%d",sum);return sum;}int Hash1(NA str){int m;n=fold(str);m=n%HASHSIZE;return m;}int Hash2(NA str){long n;int m;n = atoi(str);m=n%HASHSIZE;return m;}Status collision(int p,int c){int i,q;i=c/2+1;while(i<HASHSIZE){if(c%2==0){c++;q=(p+i*i)%HASHSIZE;if(q>=0) return q;else i=c/2+1;}else{q=(p-i*i)%HASHSIZE;c++;if(q>=0) return q;else i=c/2+1;}}return UNSUCCESS;}void benGetTime();void CreateHash1(HashTable* H,Record* a){ int i,p=-1,c,pp;system("cls"); benGetTime();for(i=0;i<NUM_BER;i++){p=Hash1(a[i].name);pp=p;while(H->elem[pp]!=NULL) {pp=collision(p,c);if(pp<0){printf("第%d记录无法解决冲突",i+1);continue;}}H->elem[pp]=&(a[i]);H->count++;printf("第%d个记录冲突次数为%d。
列车时刻表 c 数据结构设计
列车时刻表 c 数据结构设计
列车时刻表是一个重要的交通工具信息系统,它用于查
询和展示列车的发车时间、到达时间、车次编号和途经站
点等相关信息。
为了高效地存储和查询时刻表数据,我设
计了以下数据结构。
首先,我们可以使用一个哈希表来存储每个车次的信息。
哈希表的键可以使用车次编号,值则可以是一个包含该列
车所有站点信息的链表。
每个链表节点包括站点名称、到
达时间和发车时间等数据。
此外,我们还需要一个集合来存储所有的站点名称。
这
样可以方便地进行站点名称的检索和排序。
对于查询功能,我们可以利用哈希表来快速定位到指定
车次,并通过遍历链表获取该车次所有站点的信息。
对于添加新的列车时刻表数据,我们可以根据车次编号
在哈希表中插入一个新的键值对。
如果该车次已存在,则
可以将新的站点信息添加到对应链表中。
同时,我们也需
要将新的站点名称添加到站点名称的集合中。
如果需要删除某个车次的时刻表数据,我们可以在哈希表中定位到指定车次,并删除对应的键值对。
同时,我们也需要从站点名称的集合中删除该车次的所有站点名称。
这样设计的列车时刻表数据结构能够高效地存储和查询列车信息。
它允许快速定位到指定车次,同时可以方便地对车次的站点信息进行添加、删除和修改。
数据结构课程设计报告——哈希表实现电话号码查询
数据结构课程设计报告一、需求分析1问题描述:根据需要设计出合理的Hash函数,并由此建立相应的Hash表。
要求:1)每个电话用户信息包括(姓名,电话,住址)信息。
2)可以使用姓名与地址查找相应的用户信息。
3)使用Hash表实现。
使用开放定址法解决冲突。
2 基本要求:1)记录每个用户的姓名、地址和电话。
2)从键盘输入,以姓名和地址为关键字分别建立Hash表。
3)用开放地址法解决冲突。
4)分别按姓名和地址查找并显示电话号码。
二、概要设计三、详细设计typedef struct //定义结构Hash表{定义Hash表内的所有成员}HashTable[MaxSize];int Key(char x[])//关键字转换为数值{求字符数组x每个字符对应的asc值的绝对值之和,并返回最后结果}void CreateHT(HashTable ha)//创建Hash表{创建Hash表,并初始化它}void InsertHTna(HashTable ha,int &n,KeyType k,int d) //按姓名插入{以姓名为关键字,调用关键字转换函数将对应的电话号码存储到相应的存储空间。
若该位置已经被存储,则向后移一位(当移到最后一位,就移到头部继续)。
若还有冲突重复上一步。
当所有空间都查过一遍,发现没有空位,则输出“没有存储空间”。
}void InsertHTadd(HashTable ha,int &n,KeyType k,int d)//按地址插入{以地址为关键字,调用关键字转换函数将对应的电话号码存储到相应的存储空间。
若该位置已经被存储,则向后移一位(当移到最后一位,就移到头部继续)。
若还有冲突重复上一步。
当所有空间都查过一遍,发现没有空位,则输出“没有存储空间”。
}void InserHT(HashTable ha)//Hash表插入{输入用户姓名、地址和电话,分别调用按姓名插入和按地址插入函数进行插入。
哈希表的设计与实现
合肥学院计算机科学与技术系课程设计报告2007~2008学年第2学期课程数据结构与算法课程设计名称哈希表的设计与实现学生姓名学号0604011026专业班级06 计科 (1)指导教师2008年9月一、课程设计题目:(哈希表的设计与实现的问题)设计哈希表实现电话号码查询系统。
设计程序完成以下要求:( 1)设每个记录有下列数据项:电话号码、用户名、地址;(2)从键盘输入各记录,分别以电话号码和用户名为关键字建立哈希表;( 3)采用再哈希法解决冲突;(4)查找并显示给定电话号码的记录;(5)查找并显示给定用户的记录。
二、问题分析和任务定义1、问题分析要完成如下要求:设计哈希表实现电话号码查询系统。
实现本程序需要解决以下几个问题:(1)如何设计一个结点使该结点包括电话号码、用户名、地址。
(2)如何分别以电话号码和用户名为关键字建立哈希表。
(3)如何利用再哈希法解决冲突。
(4)如何实现用哈希法查找并显示给定电话号码的记录。
(5)如何查找并显示给定用户的记录。
2、任务定义由问题分析知,本设计主要要求分别以电话号码和用户名为关键字建立哈希表,并实现查找功能。
所以本设计的核心问题是如何解决散列的问题,亦即设计一个良好的哈希表。
由于结点的个数无法确认,并且如果采用线性探测法散列算法,删除结点会引起“信息丢失”的问题。
所以采用链地址法散列算法。
采用链地址法,当出现同义词冲突时,使用链表结构把同义词链接在一起,即同义词的存储地址不是散列表中其他的空地址。
首先,解决的是定义链表结点,在链地址法中,每个结点对应一个链表结点,它由三个域组成,而由于该程序需要分别用电话号码和用户名为关键字建立哈希表,所以该链表结点它是由四个域组成.name[8]、num[11]和address[20]都是char浮点型,输入输出都只能是浮点型的。
采用链地址法,其中的所有同义词构成一个单链表,再由一个表头结点指向这个单链表的第一个结点。
这些表头结点组成一个一维数组,即哈希表。
存储常用词语的数据结构设计
存储常用词语的数据结构设计
设计一个数据结构,用于存储常用词语,以便在需要时能够快速地检索和查询这些词语。
以下是我提供的一个基本的数据结构设计方案。
首先,我们可以使用字典(dictionary)数据结构来存储这些常用词语。
字典是一种键值对的数据结构,可以通过唯一的键来访问和操作对应的值。
每个常用词语可以作为一个键,对应的值可以是该词语出现的频率、相关的信息或其他我们想要存储的附加数据。
通过将常用词语作为键,我们可以使用字典的快速索引来查找和访问这些词语。
为了方便快速的检索和查询,我们可以使用哈希表来实现字典数据结构。
哈希表根据键的哈希值来存储键值对,通过哈希函数将键映射到数组的特定位置,在这个位置存储对应的值。
这样,我们可以根据键的哈希值快速地定位到对应的值。
如果我们需要存储具有相同哈希值的键,我们可以使用链表(linked list)来解决冲突。
即,在哈希表的每个位置上,我们可以使用链表来存储具有相同哈希值的键值对。
这样,在进行查找时,我们可以遍历链表来找到对应的值。
除了基本的哈希表实现,我们还可以考虑其他的改进方法,如使用自平衡二叉搜索树(balanced binary search tree)来实现字典数据结构。
自平衡二叉搜索树可以保持树的平衡,使得插入、删除和查找的时间复杂度为O(log n)。
综上所述,我们可以设计一个数据结构,使用哈希表或自平衡二叉搜索树来存储常用词语。
通过合理地选择适当的数据结构和算法,我们可以实现快速的检索和查询功能,以满足存储常用词语的需求。
【算法与数据结构】哈希表-链地址法
【算法与数据结构】哈希表-链地址法哈希表的链地址法来解决冲突问题将所有关键字为同义词的记录存储在同⼀个线性链表中,假设某哈希函数产⽣的哈希地址在区间[0, m - 1]上,则设⽴⼀个⾄振兴向量Chain ChainHash[m];数据结构//链表结点typedef struct _tagNode{int data; //元素值(关键字)struct _tagNode* next; //下⼀个结点}Node, *PNode;//哈希表结点typedef struct _tagHashTable{//这⾥⽤⼀个联合体来解释⼀下,其index也即哈希值union{int index; //哈希表index(这⾥也是哈希值)int nHashValue; //也即哈希值}INDEX;Node* firstChild; //该哈希结点在第⼀个⼦节点,即哈希值为该结点INDEX字段的struct _tagHashTable* next; //指向下⼀个哈希结点}HashTable, *PHashTable;构造哈希表,输⼊为头结点指针的引⽤//pHashTable 哈希表头结点//length 哈希表长度//pArr 关键字元素数组//nums 关键字元素数组长度void CreateHashTable(PHashTable& pHashTable, int length, int* pArr, int nums){pHashTable = new HashTable();if(NULL == pHashTable) { cerr << "Create Hashtable error! \n"; return;}pHashTable->firstChild = NULL;pHashTable->INDEX = 0;pHashTable->next = NULL;PHashTable pTemp = pHashTable;for (int i = 1; i < length; ++ i){PHashTable pt = new HashTable();if(NULL == pt) {cerr << "Create Hahstable error ! \n"; return;}pt->firstChild = NULL;pt->INDEX = i;pt->next = NULL;pTemp->next = pt;pTemp = pt;} //for//Hash(key) = key MOD length;for(int i = 0; i < nums; ++ i){//计算哈希值int nHashValue = pArr[i] % length;PHashTable pTemp2 = NULL;if(NULL != (pTemp2 = LocateHashNode(pHashTable, nHashValue)) ){Insert(pTemp2, pArr[i]);}else{cerr << "元素值为 "<< pArr[i]<< " 的元素,哈希值为 "<< nHashValue<< ", 查找其所在哈希结点失败"<<endl;}}}向某个哈希表结点(不⼀定是头结点)中插⼊元素//将关键字插⼊所在的pHashtable结点的链表//返回其在该链表上的位置(下标从1开始)int Insert(PHashTable& pHashtable, int data){if(NULL == pHashtable){cerr << "当前哈希表结点为空 \r\n"; return -1;}int nIndex = 1;PNode pNewNode = new Node();if(NULL == pNewNode){cerr << "建⽴新链表结点失败"<<endl; return -1;}pNewNode->data = data;pNewNode->next = NULL;PNode pNode = pHashtable->firstChild;if (NULL == pNode){pHashtable->firstChild = pNewNode;}else{while(pNode->next != NULL){++ nIndex;pNode = pNode->next;}++nIndex;pNode->next = pNewNode;}cout << "元素 "<< data << " 插⼊在了哈希表结点 "<< pHashtable->INDEX<< " 的第 "<< nIndex<< " 个位置"<<endl; return nIndex;}根据哈希值,返回其所在结点的指针,输⼊为表⽰该哈希表的头结点指针的引⽤//根据哈希值,返回该值应该所在的哈希表结点指针//pHashtable 哈希表头结点//nHashValue 元素的哈希值PHashTable LocateHashNode(PHashTable& pHashtable, int nHashValue){if(NULL == pHashtable) {cerr << "哈希表头结点为空"<<endl; return NULL;}PHashTable pTemp = pHashtable;do{if (pTemp->INDEX == nHashValue) return pTemp;pTemp = pTemp->next;} while (pTemp != NULL);return NULL;}从头结点为pHashtable的哈希表中,查找关键字为data,哈希值为nHashValue的元素在哈希表中的位置,返回值为在该哈希结点的链表中的位置(下标从1开始)//查找头结点为pHashtable的哈希表//其数据为data,哈希值为nHashValue的元素//在哈希表某个结点的链表中的位置(下标从1开始)int Find(PHashTable& pHashtable, int data, int nHashValue){if(NULL == pHashtable){cerr << "哈希表头结点为空"<<endl; return -1;}PHashTable pHashNode = LocateHashNode(pHashtable, nHashValue);if(NULL == pHashNode) {cerr << "找不到元素 " << data << " ,其哈希值为 "<<nHashValue<< " 在哈希表中的位置"; return -1;} int nINDEX = 1;PNode pNode = pHashNode->firstChild;if (NULL == pNode){{cerr << "找不到元素 " << data << " ,其哈希值为 "<<nHashValue<< " 在哈希表中的位置"; return -1;}}else{bool b = false;while(pNode != NULL){if(pNode->data == data){b = true;break;}++ nINDEX;pNode = pNode->next;}if (false == b){cerr << "找不到元素 " << data << " ,其哈希值为 "<<nHashValue<< " 在哈希表中的位置";return -1;}else{cout << "元素 "<< data << " 插⼊在了哈希表结点 "<< pHashNode->INDEX<< " 的第 "<< nINDEX<< " 个位置"<<endl;}}return nINDEX;}int _tmain(int argc, _TCHAR* argv[]){PHashTable pHashtable = NULL;int length = 0;int nums = 0;cout <<endl<< "请输⼊元素个数:";cin >> nums;int* pArr = new int[nums]();if(NULL == pArr) {cerr<<"申请元素空间错误"; return -1;}ZeroMemory(pArr, sizeof(int) * nums);for (int i = 0; i < nums; ++ i){int data = 0;cout << "请输⼊第 "<< i << " 个元素的值:";cin >> data;pArr[i] = data;}cout << endl<<"输⼊完毕"<<endl;cout << "请输⼊哈希表长度:";cin >> length;cout << endl <<endl <<"开始构造哈希表"<<endl; CreateHashTable(pHashtable, length, pArr, nums); cout <<endl<<"哈希表构造完毕"<<endl<<endl;cout<<endl<<endl;int value = 0;for (int i = 0; i < nums * 10; ++ i){cout << "请输⼊要查查找的元素:";cin >> value;Find(pHashtable, value, value % length);cout<<endl;}return0;}。
数据结构 第9章 查找4-哈希表
7、随机数法 Hash(key) = random ( key ) (random为伪随机函数)
适用于:关键字长度不等的情况。造表和查找都很方便。
小结:构造哈希函数的原则:
① ② ③ ④ ⑤ 执行速度(即计算哈希函数所需时间); 关键字的长度; 哈希表的大小; 关键字的分布情况; 查找频率。
三、冲突处理方法
14 H(14)=14%7=0
6个元素用7个 地址应该足够!
1
2
23 9
3
4
39 25 11
5
6
H(25)=25%7=4 H(11)=11%7=4
有冲突!
在哈希查找方法中,冲突是不可能避免的,只能 尽可能减少。
所以,哈希方法必须解决以下两个问题:
1)构造好的哈希函数
(a)所选函数尽可能简单,以便提高转换速度; (b)所选函数对关键码计算出的地址,应在哈希地址集中 大致均匀分布,以减少空间浪费。
讨论:如何进行散列查找?
根据存储时用到的散列函数H(k)表达式,迅即可查到结果! 例如,查找key=9,则访问H(9)=9号地址,若内容为9则成功; 若查不到,应当设法返回一个特殊值,例如空指针或空记录。
缺点:空间效率低!
若干术语
哈希方法 (杂凑法)
选取某个函数,依该函数按关键字计算元素的存储位置, 并按此存放;查找时,由同一个函数对给定值k计算地址, 将k与地址单元中元素关键码进行比较,确定查找是否成 功。
3. 乘余取整法
4. 数字分析法
5. 平方取中法
常用的哈希函数构造方法有:
6. 折叠法
7. 随机数法
1、直接定址法
(a、b为常数) 优点:以关键码key的某个线性函数值为哈希地址, 不会产生冲突. 缺点:要占用连续地址空间,空间效率低。
哈希表数据结构
哈希表数据结构哈希表是一种常用的数据结构,它可以将元素的添加、查找和删除的操作时间复杂度降至O(1),是一种快速、紧凑的数据结构。
它也可以被用于存储大量的键值对,如字典或者关联数组。
哈希表的内部结构有不同的实现方式,可以根据不同的实现方法达到不同的性能。
本文将详细介绍哈希表的背景、实现方式和应用等内容,以期使读者对哈希表有更深入的理解。
一、哈希表的概念哈希表是一种索引定位数据的数据结构。
哈希表(又称散列表)使用一种称为哈希函数的函数,根据键来计算出一个索引值,然后将值存储在数组的指定位置。
由于其有效的搜索时间,哈希表在许多不同的应用程序中被广泛的使用。
二、哈希表的实现方式哈希表的实现方式有多种,如拉链法、开放寻址法等,但其常用的实现方式为拉链法。
(1)拉链法拉链法是最基本的哈希表实现方式,它将散列值相同的键值(元素)存储在链表中,当需要查找或添加元素时只需要在链表中进行查找和操作,从而达到减少对查找和添加的时间复杂度。
拉链法中每个数组位置上存放一个链表的指针,链表中的每个节点中存放着存储的元素。
(2)开放寻址法开放寻址法是一种空间换时间的实现方式,它首先将输入的元素通过哈希函数映射成一个数组下标,如果该数组位置已经有数据存在,则重新使用哈希函数映射得到一个新的下标,直到找到一个没有被占用的位置将元素存放进去,以此来解决碰撞问题。
三、哈希表的应用哈希表在计算机科学中有着广泛的应用,它可以用来存储、查询和管理大量的键值对,如字典或者关联数组,减少查找的时间复杂度。
同时它也可以被用来存储表格数据,将表格转换成哈希表,使得查询性能更优。
此外,哈希表还可以被用来实现复杂的数据结构,如字典树,它可以帮助我们快速查询字符串是否存在。
总结哈希表是一种常用的数据结构,它可以将元素的添加、查找和删除的操作时间复杂度降至O(1),是一种快速、紧凑的数据结构。
它的实现方式主要有拉链法和开放寻址法,广泛应用于字典的存储、表格的查询和复杂的数据结构的实现等等。
哈希表是有序还是无序的 哈希表底层的数据结构实现 哈希表的构造算法 哈希表解决冲突的方法
哈希表是有序还是无序的哈希表底层的数据结构实现哈希表的构造算法哈希表解决冲突的方法1. 引言1.1 概述哈希表是一种使用哈希函数和数组来实现的数据结构,具有高效的查找和插入操作的优点。
它通过将关键字映射到数组中的位置来实现快速查找。
在计算机科学领域中,哈希表被广泛应用于各种场景,如数据库索引、缓存、字典等。
本文将对哈希表的一些重要问题进行讨论和探究,包括哈希表是有序还是无序的问题、哈希表底层的数据结构实现、哈希表的构造算法以及解决冲突的方法。
通过深入研究这些问题,我们可以更好地理解和应用哈希表。
1.2 文章结构本文共分为六个部分,每个部分都涵盖了特定主题:第一部分为引言部分,介绍了文章的背景、目的以及整体结构。
第二部分将探讨哈希表是有序还是无序的问题。
我们首先对哈希表的定义和功能进行概述,然后讨论了哈希表顺序性问题可能存在的原因,并综合相关研究和理论观点进行综述。
第三部分将集中讨论哈希表底层的数据结构实现。
我们将介绍使用数组和链表来实现哈希表底层数据结构的方法,并讨论其他可能用于哈希表底层的数据结构。
第四部分将详细介绍哈希表的构造算法。
我们将比较常见的哈希函数算法及其特点,然后综述和分析不同碰撞处理算法,并探讨构造算法在不同应用场景中的优化方法。
第五部分将重点解决哈希表冲突的方法。
我们将介绍开放地址法(如线性探测、二次探测等)以及链地址法和拉链法,并讨论其他可能的冲突解决方法。
最后一部分为结论部分,对哈希表的优缺点进行总结,并对哈希表有序性问题、底层数据结构实现、构造算法和冲突解决方法进行总结与展望。
1.3 目的本文旨在通过对哈希表有序性问题、底层数据结构实现、构造算法和冲突解决方法等方面进行深入研究,以期能够更加全面地理解和应用哈希表。
通过本文的阐述,读者将能够了解到不同问题背后所涉及到的相关理论和算法,并能够在实践中灵活应用哈希表,提高数据结构的效率及性能。
2. 哈希表是有序还是无序的2.1 哈希表的定义和功能哈希表(Hash Table)是一种常用的数据结构,用于存储键值对。
详解数据结构之散列(哈希)表
详解数据结构之散列(哈希)表1.散列表查找步骤散列表,最有用的基本数据结构之一。
是根据关键码的值直接进行访问的数据结构,散列表的实现常常叫做散列(hasing)。
散列是一种用于以常数平均时间执行插入、删除和查找的技术,下面我们来看一下散列过程。
我们的整个散列过程主要分为两步:1.通过散列函数计算记录的散列地址,并按此散列地址存储该记录。
就好比麻辣鱼,我们就让它在川菜区,糖醋鱼,我们就让它在鲁菜区。
但是我们需要注意的是,无论什么记录我们都需要用同一个散列函数计算地址,然后再存储。
2.当我们查找时,我们通过同样的散列函数计算记录的散列地址,按此散列地址访问该记录。
因为我们存和取的时候用的都是一个散列函数,因此结果肯定相同。
刚才我们在散列过程中提到了散列函数,那么散列函数是什么呢?我们假设某个函数为f,使得存储位置= f (key) ,那样我们就能通过查找关键字不需要比较就可获得需要的记录的存储位置。
这种存储技术被称为散列技术。
散列技术是在通过记录的存储位置和它的关键字之间建立一个确定的对应关系 f ,使得每个关键字key 都对应一个存储位置f(key)。
见下图这里的 f 就是我们所说的散列函数(哈希)函数。
我们利用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间就是我们本文的主人公------散列(哈希)上图为我们描述了用散列函数将关键字映射到散列表。
但是大家有没有考虑到这种情况,那就是将关键字映射到同一个槽中的情况,即f(k4) = f(k3) 时。
这种情况我们将其称之为冲突,k3 和k4 则被称之为散列函数 f 的同义词,如果产生这种情况,则会让我们查找错误。
幸运的是我们能找到有效的方法解决冲突。
首先我们可以对哈希函数下手,我们可以精心设计哈希函数,让其尽可能少的产生冲突,所以我们创建哈希函数时应遵循以下规则:1.必须是一致的。
假设你输入辣子鸡丁时得到的是在看,那么每次输入辣子鸡丁时,得到的也必须为在看。
hash表
hash表哈希表是计算机科学中常见的数据结构,也称为散列表。
哈希表是由一个数组和一个哈希函数组成的数据结构,其中数组的每个元素被称为“哈希桶”,哈希函数用于计算元素索引,这个索引通常称为“哈希码”,该索引用于在数组中定位正确的哈希桶。
哈希表的设计目标是提供一种在常数时间内完成查找、插入和删除操作的数据结构,因此它通常被用作高效的字典数据结构。
哈希表的基本操作包括put(插入)、get(查找)和delete(删除)。
在哈希表中,元素的索引是根据哈希函数的计算结果得出的。
哈希函数是将输入值(元素)映射到哈希码的函数,哈希函数应该满足的性质是它应该是一致的,即对于同一个输入,哈希函数应该总是返回相同的哈希码,在不同的输入之间,哈希函数应该尽可能地让哈希码分布均衡。
同一个哈希码可能是由不同的输入得出的,这种情况在哈希表中称为“哈希冲突”,哈希冲突的解决方法有开放式寻址和链表法。
在开放式寻址中,当一个哈希冲突发生时,它会尝试向后遍历桶数组,选择第一个空桶,并在这个桶中插入元素。
如果该桶被另一个元素占据,就尝试下一个空桶,如果整个数组被遍历完毕,那么原来的插入操作就失败了。
在开放式寻址中,哈希表中的元素被紧密地存储,所以这种方法较适用于内存空间较小的情况,但这种方法的缺点是在高度填满的哈希表中,访问哈希表的效率会显著降低,并且哈希表中的操作也变得非常耗时。
在链表法中,数组每个位置都是一个链表的头结点,当哈希冲突发生时,新的元素会被插入到对应桶中的链表末尾。
链表法是一种天然并行的数据结构,它允许在同一桶内的元素并行地插入和删除,并且支持调整哈希表的负载因子,使哈希表在高度填充时的性能保持稳定。
但是,链表法的缺点是每个元素都需要存储一个指向下一个元素的指针,在大型哈希表中会占用大量的内存空间。
除了以上两种解决哈希冲突的方法,还有一些其他的方法被广泛地应用在哈希表中,比如线性探测和双重哈希等算法。
线性探测是一种开放式寻址算法,它尝试寻找下一个可用的哈希桶作为冲突的解决方法。
数据结构 哈希表的构建
哈希表是一种基于哈希函数进行快速访问的数据结构,它可以在常数时间复杂度下进行插入、删除和查找操作。
下面是构建哈希表的一般步骤:
1. 定义哈希表的大小:首先,确定哈希表的大小,即桶的数量。
桶的数量应该是一个较大的素数,以减少哈希冲突。
2. 设计哈希函数:哈希函数是将输入的键转换为桶的索引的算法。
一个好的哈希函数应该能够将键均匀地映射到不同的桶中,以减少冲突。
常见的哈希函数包括除留余数法、乘法哈希法、平方取中法等。
3. 创建桶:根据确定的哈希表大小,创建相应数量的桶。
4. 插入操作:将键值对插入哈希表时,首先使用哈希函数计算出键对应的桶索引。
如果该桶为空,则将键值对插入该桶中;如果该桶非空,则发生冲突,需要解决冲突,常见的解决方法包括链地址法和开放地址法。
5. 查找操作:在查找键值对时,同样使用哈希函数计算出键对应的桶索引。
若该桶为空,则键不存在于哈希表中;若该桶非空,则可能存在冲突,需要在该桶中进行线性搜索或其他冲突解决方法来找到对应的值。
6. 删除操作:删除键值对时,先找到键对应的桶,然后删除桶中的键值对。
在实际应用中,为了提高哈希表的性能,通常还会考虑哈希表的动态扩容和缩容、哈希函数的设计优化、冲突解决策略的选择等问题。
严蔚敏数据结构课件10:哈希表
1. 直接定址法
此类函数直接取关键字或关键字的某个线性函数 线性函数值 线性函数 作为散列地址: Hash ( key ) = a * key + b { a, b为常数 } 这类散列函数是一对一的映射,一般不会产生冲突。 但是,它要求散列地址空间的大小与关键字集合的 大小相同。
2. 数字分析法 设有n个d位数,每一位可能有r种不同的符号。这 r 种不同的符号在各位上出现的频率不一定相同,可能 在某些位上分布均匀些;在某些位上分布不均匀,只 有某几种符号经常出现。可根据散列表的大小,选取 其中各种符号分布均匀的若干位作为散列地址。
查找关键字时所需对桶的平均访问次数
从图中可以看出,链地址法优于开放定址法;在散列函 数中,用除留余数法作散列函数优于其它类型的散列函 数,最差的是折叠法。
用不同的方法溢出处理冲突时散列表的平均查找长度 如图所示
处 理 溢 出 的 方 法 开 放 定 址 法 伪随机探查法 二次探查法 双散列法 链 地 址 法 (同义词子表法)
1 + α 2
平 均 搜 索 长 度 ASL 搜索成功 Sn
1 1 1 + 2 1 − α
搜索不成功(登入新记录) Un
1 2 1 1 + 2 (1 − α )
线性探查法
1 − log α
e (1 − α )
1 1− α
α + e −α ≈ α
散列 (Hashing)
在线性表、树结构中查找纪录是通过与关键 字的“比较”完成的。
• 顺序查找,比较的结果为“=”或“≠” • 非顺序查找,比较的结果为“<”,“=”,“>”
散列的思想: 根据纪录的关键字直接找到记录的存储位置, 即为关键字和记录的存储位置建立一个对应 关系f,使每个关键字和结构中一个唯一的 存储位置相对应。 对应关系f为散列函数,按该思想建立的表 为散列表。
数据结构课程设计参考题目(一)
数据结构课程设计参考题目(一)数据结构是计算机科学中的一门基础课程,它主要研究数据的组织、存储、管理和操作等方面的问题。
随着计算机技术的发展,数据结构逐渐成为各个领域必不可少的一门课程。
而数据结构课程设计参考题目是该课程的一项重要内容,它能够帮助学生更好地掌握课程知识,提高对数据结构的理解和应用能力。
以下是几个数据结构课程设计参考题目。
1.链表操作设计一个链表类,使得它能够实现插入、删除、查找和遍历链表的操作。
要求采用单向链表或双向链表实现,并考虑链表的循环操作。
同时,要求能够对链表进行排序操作。
2.栈与队列操作设计一个栈和队列类,使得它们能够实现入栈、出栈、入队和出队的操作。
要求采用数组或链表实现,并可用于表达式转换和括号匹配等相关问题。
3.堆排序算法实现堆排序算法,要求能够对整型数列进行排序,并输出其排序后的结果。
要求堆的构建、删除和调整操作均可用最大堆或最小堆实现。
同时,要求能够对算法的时间复杂度进行分析,并与快速排序等算法进行比较。
4.哈希表实现设计一个哈希表类,使其能够实现插入、删除和查找等操作。
要求采用链地址法或开放地址法实现,同时需要考虑哈希函数和扩容等问题。
要求能够对哈希冲突的解决方法进行比较和分析。
5.树与图的遍历实现二叉树、B树或B+树的遍历操作,要求能够实现先序、中序和后序遍历,并能够循环遍历或递归遍历。
同时,要求能够对树的平衡性进行探究和讨论。
另外,树的遍历也是图的遍历的基础,可以通过深度优先搜索或广度优先搜索实现图的遍历。
以上是一些常见的数据结构课程设计参考题目,它们可以锻炼学生的编程能力、算法分析能力和数据处理能力,同时也可以增强学生对数据结构知识的理解和掌握。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验六:存储管理、查找和排序题目:哈希表设计班级:姓名:学号:一、问题描述针对某个集体(比如你所在的班级)中的“人名”设计一个哈希表,使得平均查找长度均不超过R,完成相应的建表和查表顺序。
二、基本要求假设人名为中国人姓名的汉语拼音形式。
待填入哈希表的人名共有30个,取平均查找长度的上限为2。
哈希函数用除留余数法构造,用伪随机探测再散列法处理冲突。
三、概要设计1.构造结构体:typedef struct{};2.姓名表的初始化:void InitNameTable();3.建立哈希表:void CreateHashTable();4.显示姓名表:void DisplayNameTable();5.姓名查找:void FindName();6.主函数:void main() ;四、详细设计1.姓名表的初始化void InitNameTable(){NameTable[0].py="louyuhong";NameTable[1].py="shenyinghong";NameTable[2].py="wangqi";NameTable[3].py="zhuxiaotong";NameTable[4].py="zhataotao";NameTable[5].py="chenbinjie";NameTable[6].py="chenchaoqun";NameTable[7].py="chencheng";NameTable[8].py="chenjie";NameTable[9].py="chenweida";NameTable[10].py="shanjianfeng"; NameTable[11].py="fangyixin";NameTable[12].py="houfeng";NameTable[13].py="hujiaming";NameTable[14].py="huangjiaju"; NameTable[15].py="huanqingsong"; NameTable[16].py="jianghe";NameTable[17].py="jinleicheng"; NameTable[18].py="libiao";NameTable[19].py="liqi";NameTable[20].py="lirenhua";NameTable[21].py="liukai";NameTable[22].py="louhanglin"; NameTable[23].py="luchaoming"; NameTable[24].py="luqiuwei";NameTable[25].py="panhaijian"; NameTable[26].py="shuxiang";NameTable[27].py="suxiaolei";NameTable[28].py="sunyubo";NameTable[29].py="wangwei";for (i=0;i<NAME_LEN;i++) //将字符串的各个字符所对应的ASCII 码相加,所得的整数做为哈希表的关键字{int s=0;char *p=NameTable[i].py;for (j=0;*(p+j)!='\0';j++)s+=toascii(*(p+j));NameTable[i].m=s;}}2.建立哈希表void CreateHashTable(){for(i=0;i<HASH_LEN;i++){HashTable[i].py="\0";HashTable[i].m =0;HashTable[i].si=0;}for(i=0;i<NAME_LEN;i++){int sum=1,j=0;int adr=(NameTable[i].m)%P; //除留余数法H(key)=key MOD p,p<=mif(HashTable[adr].si==0) //如果不冲突,将姓名表赋值给哈希表{HashTable[adr].m =NameTable[i].m;HashTable[adr].py=NameTable[i].py;HashTable[adr].si=1;}else//如果冲突{while(HashTable[adr].si!=0){adr=(adr+d[j++])%HASH_LE N; //伪随机探测再散列法处理冲突sum=sum+1;//查找次数加1}HashTable[adr].m =NameTable[i].m; //将姓名表复制给哈希表对应的位置上HashTable[adr].py=NameTable[i].py;HashTable[adr].si=sum;}}}3.显示姓名表与哈希表void DisplayNameTable(){printf("\n地址 \t\t 姓名 \t\t 关键字\n");for (i=0;i<NAME_LEN;i++)printf("%2d %18s\t\t %d \n",i,NameTable[i].py,NameTable[i].m);}void DisplayHashTable(){float asl=0.0;printf("\n\n 地址 \t\t 姓名 \t\t 关键字 \t 搜索长度\n"); //显示的格式for (i=0;i<HASH_LEN;i++){printf("%2d %18s \t\t %d\t\t %d\n",i,HashTable[i].py,HashTable[i].m,HashTable[i].si);asl+=HashTable[i].si;}asl/=NAME_LEN; //求得ASLprintf("\n\n平均查找长度:ASL(%d)=%f \n",NAME_LEN,asl);}4.姓名查找void FindName(){char name[20]={0};int s=0,sum=1,adr;printf("\n请输入想要查找的姓名的拼音:");scanf("%s",name);for (j=0;j<20;j++) //求出姓名的拼音所对应的ASCII作为关键字s+=toascii(name[j]);adr=s%P; //除留余数法j=0;if(HashTable[adr].m==s&&!strcmp(HashTable[adr].py,name)) //分3种情况进行判断,并输出超找结果printf("\n姓名:%s 关键字:%d 查找长度为:1\n",HashTable[adr].py,s);else if (HashTable[adr].m==0)printf("没有想要查找的人!\n");else{while(1){adr=(adr+d[j++])%HASH_LEN; //伪随机探测再散列法处理冲突sum=sum+1;//查找次数加1if(HashTable[adr].m==0){printf("没有想要查找的人!\n");break;}if(HashTable[adr].m==s&&!strcmp(HashTa ble[adr].py,name)){printf("\n姓名:%s 关键字:%d 查找长度为:%d\n",HashTable[adr].py,s,sum);break;}}}}五、测试结果六、实验环境C-Free七、源程序代码#include<stdio.h>#include<time.h> //time用到的头文件#include<stdlib.h> //随机数用到的头文件#include<ctype.h> //toascii()用到的头文件#include<string.h> //查找姓名时比较用的头文件#define HASH_LEN 50 //哈希表的长度#define P 47 //小于哈希表长度的P #define NAME_LEN 30 //姓名表的长度typedef struct //姓名表{char *py; //名字的拼音int m; //拼音所对应的}NAME;NAME NameTable[HASH_LEN]; //全局定义姓名表typedef struct //哈希表{char *py; //名字的拼音int m; //拼音所对应的ASCII总和int si; //查找长度}HASH;HASH HashTable[HASH_LEN]; //全局定义哈希表int d[30],i,j; //全局定义随机数,循环用的i、jvoid InitNameTable() //姓名表的初始化{NameTable[0].py="louyuhong";NameTable[1].py="shenyinghong"; NameTable[2].py="wangqi";NameTable[3].py="zhuxiaotong"; NameTable[4].py="zhataotao";NameTable[5].py="chenbinjie";NameTable[6].py="chenchaoqun";NameTable[7].py="chencheng";NameTable[8].py="chenjie";NameTable[9].py="chenweida";NameTable[10].py="shanjianfeng";NameTable[11].py="fangyixin";NameTable[12].py="houfeng";NameTable[13].py="hujiaming";NameTable[14].py="huangjiaju";NameTable[15].py="huanqingsong"; NameTable[16].py="jianghe";NameTable[17].py="jinleicheng";NameTable[18].py="libiao";NameTable[19].py="liqi";NameTable[20].py="lirenhua";NameTable[21].py="liukai";NameTable[22].py="louhanglin";NameTable[23].py="luchaoming";NameTable[24].py="luqiuwei";NameTable[25].py="panhaijian";NameTable[26].py="shuxiang";NameTable[27].py="suxiaolei";NameTable[28].py="sunyubo";NameTable[29].py="wangwei";for (i=0;i<NAME_LEN;i++) //将字符串的各个字符所对应的ASCII码相加,所得的整数做为哈希表的关键字{int s=0;char *p=NameTable[i].py;for (j=0;*(p+j)!='\0';j++)s+=toascii(*(p+j));NameTable[i].m=s;}}void CreateHashTable() //建立哈希表{for(i=0;i<HASH_LEN;i++){HashTable[i].py="\0";HashTable[i].m =0;HashTable[i].si=0;}for(i=0;i<NAME_LEN;i++){int sum=1,j=0;int adr=(NameTable[i].m)%P; //除留余数法 H(key)=key MOD p,p<=m if(HashTable[adr].si==0) //如果不冲突,将姓名表赋值给哈希表 {HashTable[adr].m =NameTable[i].m;HashTable[adr].py=NameTable[i].py;HashTable[adr].si=1;}else //如果冲突{while(HashTable[adr].si!=0){adr=(adr+d[j++])%HASH_LEN; //伪随机探测再散列法处理冲突sum=sum+1; //查找次数加1}HashTable[adr].m =NameTable[i].m; //将姓名表复制给哈希表对应的位置上HashTable[adr].py=NameTable[i].py;HashTable[adr].si=sum;}}}void DisplayNameTable() //显示姓名表{printf("\n地址 \t\t 姓名 \t\t 关键字\n");for (i=0;i<NAME_LEN;i++)printf("%2d %18s \t\t %d \n",i,NameTable[i].py,NameTable[i].m);}void DisplayHashTable() // 显示哈希表{float asl=0.0;printf("\n\n 地址 \t\t 姓名 \t\t 关键字 \t 搜索长度\n"); //显示的格式 for (i=0;i<HASH_LEN;i++){printf("%2d %18s \t\t %d\t\t %d\n",i,HashTable[i].py,HashTable[i].m,HashTable[i].si);asl+=HashTable[i].si;}asl/=NAME_LEN; //求得ASLprintf("\n\n平均查找长度:ASL(%d)=%f \n",NAME_LEN,asl);}void FindName() //查找{char name[20]={0};int s=0,sum=1,adr;printf("\n请输入想要查找的姓名的拼音:");scanf("%s",name);for (j=0;j<20;j++) //求出姓名的拼音所对应的ASCII作为关键字s+=toascii(name[j]);adr=s%P; //除留余数法j=0;if(HashTable[adr].m==s&&!strcmp(HashTable[adr].py,name)) //分3种情况进行判断,并输出超找结果printf("\n姓名:%s 关键字:%d 查找长度为: 1\n",HashTable[adr].py,s); else if (HashTable[adr].m==0)printf("没有想要查找的人!\n");else{while(1){adr=(adr+d[j++])%HASH_LEN; //伪随机探测再散列法处理冲突sum=sum+1; //查找次数加1if(HashTable[adr].m==0){printf("没有想要查找的人!\n");break;}if(HashTable[adr].m==s&&!strcmp(HashTable[adr].py,name)) {printf("\n姓名:%s 关键字:%d 查找长度为:%d\n",HashTable[adr].py,s,sum);break;}}}}int main() //主函数{char a;srand((int)time(0));for(i=0;i<30;i++) //用随机函数求得伪随机数列d[i](在1到50之间)d[i]=1+(int)(HASH_LEN*rand()/(RAND_MAX+1.0));InitNameTable();CreateHashTable();puts(" 哈希表设计");//显示菜单栏start:puts("\n*----------------------------菜单栏------------------------------*");puts(" \t\t\t 1. 显示姓名表");puts(" \t\t\t 2. 显示哈希表");puts(" \t\t\t 3. 查找");puts(" \t\t\t 4. 退出 ");puts("*----------------------------------------------------------------*"); restart:printf("\n\t请选择:");scanf("%s",&a);switch(a) //根据选择进行判断,直到选择退出时才可以退出 {case '1':DisplayNameTable();break;case '2':DisplayHashTable();break;case '3':FindName();break;case '4':exit(0);break;default:printf("\n请输入正确的选择!\n");goto restart;}goto start;}。