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,"houhuiyu");//侯慧玉
strcpy(NAME[1].s,"liutongxuan");//刘同轩
strcpy(NAME[2].s,"liujiyuan");//刘继源
strcpy(NAME[3].s,"wuzhe");//吴哲
strcpy(NAME[4].s,"yaofanqi");//姚蕃淇
strcpy(NAME[5].s,"sunchuwen");//孙楚旻
strcpy(NAME[6].s,"songmingxue");//宋明雪
strcpy(NAME[7].s,"zhangyongfei");//张勇飞
strcpy(NAME[8].s,"zhangnanshuang");//张楠爽
strcpy(NAME[9].s,"xumingyan");//徐明燕
strcpy(NAME[10].s,"zengguangxun");//曾广巡
strcpy(NAME[11].s,"liyong");//李勇
strcpy(NAME[12].s,"liwenyao");//李文瑶
strcpy(NAME[13].s,"lichenchuangyi");//李陈创一
strcpy(NAME[14].s,"yangbinxu");//杨滨旭
strcpy(NAME[15].s,"sangtianqi");//桑天奇
strcpy(NAME[16].s,"lianghongting");//梁宏婷
strcpy(NAME[17].s,"wangfuqiang");//王富强
strcpy(NAME[18].s,"wanghongyuan");//王洪远
strcpy(NAME[19].s,"wangtongshu");//王童姝
strcpy(NAME[20].s,"wangpeng");//王鹏
strcpy(NAME[21].s,"aizhanpeng"); //艾展鹏
strcpy(NAME[22].s,"yuanyuan");//袁媛
strcpy(NAME[23].s,"hexinlin");//贺薪霖
strcpy(NAME[24].s,"xinghongxuan");//邢鸿轩
strcpy(NAME[25].s,"guofanshu");//郭芃妤
strcpy(NAME[26].s,"chenxuyan");//陈旭艳
strcpy(NAME[27].s,"hanyutao");//韩玉涛
strcpy(NAME[28].s,"lushiteng");//鹿世腾
strcpy(NAME[29].s,"huangqichang");//黄启昌
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;
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+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+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("\t汉字姓名拼音哈希表展示查找系统\n");
printf("\t1.展示姓名拼音和关键字\n");
printf("\t2.展示哈希表\n");
printf("\t3.查找关键字\n");
printf("\t4.退出\n");
printf("\n");
printf("\n");
return 0;
}
int main()
{
int 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)查找姓名:
7 结果分析
时间复杂度在没有冲突时是O(1),实际上要根据冲突多少来确定,最差情况下会退化成O(n)。空间复杂度是O(n)。