数据结构实训——哈希表设计
1 课题描述
针对某个集体中人名设计一个哈希表,使得平均查找长度不超过2,并完成相应的建表和查表程序。
2 问题分析和任务定义
1)假设人名为中国人姓名的汉语拼音形式。待填入哈希表的人名共有30个,取平均查找长度的上限为2。
2)哈希函数用除留余数法构造,用线性探测再散列法或链地址法处理冲突。
3) 在输入人名过程中能自动识别非法输入,并给与非法输入的反馈信息要求重新输入。
4)查找成功时,显示姓名及关键字,并计算和输出查找成功的平均查找长度
3 逻辑设计
1)数据类型:
对于名字中包含的信息,名字的拼音使用字符串类型保存,由拼音字母ascll构成的关键字使用整数型保存。对于哈希表所包含的信息,姓名使用字符串类型保存,关键字使用整数型保存,哈希表中的元素使用整数类型保存。
struct name///名字结构体
{
char s[30];
int v;///ascll码值之和
} NAME[N];
struct hashs///哈希表结构体
{
char name[30];///名字
int key;///关键字
int sum;///哈希表中含有的元素个数
} HASH[M];
2)抽象数据类型:
ADT Hash {
数据对象D:D是具有相同特征的数据元素的集合。各数据元素均含有类型相同,可唯一标识数据元素的关键字。
数据关系R:数据元素同属一个集合。
init()
操作结果:初始化姓名表。
creathash()
操作结果:建立哈希表。
displayhash()
操作结果:显示哈希表。
display()
操作结果:显示姓名表。
searchhash()
操作结果:查找姓名。
}ADT Hash
3)模块功能:
功能上主要分为初始化姓名表,构建哈希表,显示姓名表,显示哈希表,从哈希表中
查找姓名这五大功能。其中构建哈希表使用除留余数法构建,并用线性探测再散列的方法解决冲突。
4 详细设计
{定义相应的存储结构并写出各函数的伪码算法。在这个过程中,要综合考虑系统功能,使得系统结构清晰、合理、简单和易于调试,抽象数据类型的实现尽可能做到数据封装,基本操作的规格说明尽可能明确具体。详细设计的结果是对数据结构和基本操作做出进一步的求精,写出数据存储结构的类型定义,写出函数形式的算法框架}
const int N=30;
const int M=50;
struct name///名字结构体
{
char s[30];
int v;///ascll码值之和
} NAME[N];
struct hashs///哈希表结构体
{
char name[30];///名字
int key;///关键字
int sum;///哈希表中含有的元素个数
} HASH[M];
<1>初始化函数:void init()
读取姓名信息,初始化成姓名表。
<2>创建哈希表函数:void creathash()
将读取信息建立的姓名表建立哈希表。
<3>演示哈希表函数:void displayhash()
打印哈希表中的信息。
<4>演示姓名表函数:void display()
打印姓名表中的信息。
<5>查找哈希表中的姓名函数 void searchhash()
按照输入的姓名查找其在哈希表中的位置,并打印信息。
5 程序代码
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=30; const int M=50; struct name///名字结构体 { char s[30]; int v;///ascll码值之和 } NAME[N]; struct hashs///哈希表结构体 { char name[30];///名字 int key;///关键字 int sum;///哈希表中含有的元素个数 } HASH[M]; void init()///初始化 { int i,j,sum; for(i=0; i<N; i++) { NAME[i].v=0; } strcpy(NAME[0].s,"chenliang");//陈亮 strcpy(NAME[1].s,"chenyuanhao");//陈元浩 strcpy(NAME[2].s,"chengwenliang");//程文亮 strcpy(NAME[3].s,"dinglei");//丁磊 strcpy(NAME[4].s,"fenghanzao");//冯汉枣 strcpy(NAME[5].s,"fuzongkai");//付宗楷 strcpy(NAME[6].s,"hujingbin");//胡劲斌 strcpy(NAME[7].s,"huangjianwu");//黄建武 strcpy(NAME[8].s,"lailaifa");//赖来发 strcpy(NAME[9].s,"lijiahao");//李嘉豪 strcpy(NAME[10].s,"liangxiaocong");//梁晓聪 strcpy(NAME[11].s,"linchunhua");//林春华 strcpy(NAME[12].s,"liujianhui");//刘建辉 strcpy(NAME[13].s,"luzhijian");//卢志健 strcpy(NAME[14].s,"luonan");//罗楠 strcpy(NAME[15].s,"quegaoxiang");//阙高翔 strcpy(NAME[16].s,"sugan");//苏淦 strcpy(NAME[17].s,"suzhiqiang");//苏志强 strcpy(NAME[18].s,"taojiayang");//陶嘉阳 strcpy(NAME[19].s,"wujiawen");//吴嘉文 strcpy(NAME[20].s,"xiaozhuomin");//肖卓明 strcpy(NAME[21].s,"xujinfeng"); //许金峰 strcpy(NAME[22].s,"yanghaichun");//杨海春 strcpy(NAME[23].s,"yeweixiong");//叶维雄 strcpy(NAME[24].s,"zengwei");//曾玮 strcpy(NAME[25].s,"zhengyongbin");//郑雍斌 strcpy(NAME[26].s,"zhongminghua");//钟明华 strcpy(NAME[27].s,"chenliyan");//陈利燕 strcpy(NAME[28].s,"liuxiaohui");//刘晓慧 strcpy(NAME[29].s,"panjinmei");//潘金梅 for(i=0; i<N; i++) { sum=0; for(j=0; j<strlen(NAME[i].s); j++) { sum=sum+(NAME[i].s[j]-'a'); } NAME[i].v=sum;///名字字母ascll码之和 } } void creathash()///构造哈希表 { int i,j; int n,m,counts; for(i=0; i<M; i++) { strcpy(HASH[i].name,"0"); HASH[i].key=0; HASH[i].sum=0; } for(i=0; i<N; i++) { counts=1; n=(NAME[i].v)%47; m=n; if(HASH[n].sum==0)///不冲突 { strcpy(HASH[n].name,NAME[i].s); HASH[n].key=NAME[i].v; HASH[n].sum=1; } else///如果发生了冲突 { while(1) { m=(m+(NAME[i].v%10)+1)%47; counts++; if(HASH[m].key==0) { break; } } strcpy(HASH[m].name,NAME[i].s); HASH[m].key=NAME[i].v; HASH[m].sum=counts; } } return ; } void searchhash() { char name[30]; int i,sum,n,m,counts; sum=0; n=0; counts=1; printf("请输入要查找人的姓名拼音:\n"); scanf("%s",&name); for(i=0; i<strlen(name); i++) { sum+=(name[i]-'a'); } n=sum%47; m=n; if(strcmp(HASH[n].name,name)==0) { printf("姓名:%s 关键字:%d 查找长度:1\n",HASH[n].name,sum); } else if(HASH[n].sum==0) { printf("没有找到这条记录!!!\n"); } else { while(1) { m=(m+(sum%10)+1)%47;///哈希函数 counts++; if(strcmp(HASH[m].name,name)==0) { printf("姓名:%s 关键字:%d 查找长度:%d\n",HASH[m].name,sum,counts); break; } if(HASH[m].key==0) { printf("没有找到这条记录!!!\n"); break; } } } } void displayhash()///演示哈希表 { int i,sum; float ave; ave=0.0; sum=0; printf("\n地址\t关键字\t\t搜索长度\t姓名\n"); for(i=0; i<M; i++) { printf("%d",i); printf("\t%d",HASH[i].key); printf("\t\t%d",HASH[i].sum); printf("\t%s",HASH[i].name); printf("\n"); } for(i=0; i<M; i++) { sum+=HASH[i].sum; } ave=((sum)*1.0)/N; printf("\n"); printf("平均查找长度ASL(%d)=%.3lf\n",N,ave); return ; } void display() { int i; for(i=0; i<30; i++) { printf("\n\t关键字\t\t姓名\n"); printf("\t%d",NAME[i].v); printf("\t%s",NAME[i].s); } return ; } int menu() { printf("\n\n"); printf(" *****汉字姓名拼音哈希表展示查找系统*****\n"); printf(" ***1.展示姓名拼音和关键字 ***\n"); printf(" ***2.展示哈希表 ***\n"); printf(" ***3.查找关键字 ***\n"); printf(" ***4.退出 ***\n"); printf(" ****************************************\n"); printf("\n"); return 0; } int main() { int i,n; int flag; flag=1; while(1) { menu(); if(flag==1) { init(); creathash(); flag=0; } scanf("%d",&n); getchar(); if(n<1||n>4) { printf("输入有误,请重新输入!!!\n"); continue; } else { if(n==1) { printf("展示所准备的姓名拼音及其所组成的关键字:\n"); display(); } else if(n==2) { displayhash(); } else if(n==3) { searchhash(); } else if(n==4) { return 0; } } } return 0; }
6 程序调试与测试
1)打印姓名表:
2)打印哈希表
3)查找姓名: