[问题描述]
针对某个集体中人名设计一个哈希表,使得平均查找长度不超过2,并完成相应的建表和查表程序。
[基本要求]
假设人名为中国人姓名的汉语拼音形式。待填入哈希表的人名共有30个,取平均查找长度的上限为2。哈希函数用除留余数法构造,用线性探测再散列法或链地址法处理冲突。
[测试数据]
取自己周围较熟悉的30个人名。
[选作内容]
(1) 从教科书上介绍的集中哈希函数构造方法中选出适用者并设计几个不同的哈希函数,比较他们的地址冲突率(可以用更大的名字集合作实验)。
(2) 研究这30个人名的特点,努力找一个哈希函数,使得对于不同的拼音名一定不发生地址冲突。
(3)在哈希函数确定的前提下尝试各种不同处理冲突的方法,考察平均查找长度的变化和造好的哈希表中关键字的聚集性。
[代码实现]文章来源:https://www.toymoban.com/news/detail-502832.html
/*
0!='0'
*/
#include<queue>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define scnaf scanf
#define ll long long
const int N=1000;
int n=30,l=0x3f3f3f3f,r=0,flag,cut=0;
char s[N][20],x[20];
int hashnum1(int k)//1.hash函数|取余法
{
r=max(r,k%31+1);
l=min(l,k%31+1);
return k%31+1;
}
int hashnum2(int k)//2.hash函数|数字分析法
{
int p,i=1,t=0;
while(k)
{
p=k%10;
if(i<3)
t+=p*i++;
else t+=p*i--;
k/=10;
}
r=max(r,t);//
l=min(l,t);
return t;//
}
int hashnum3(char asc[])//直接定址法,该法针对所给30个人名样本不产生冲突
{
int p=0,i,j;
for(i=0,j=0;asc[i];i++,j++)
p+=asc[i]*i;
p=(p/1000*10+p/100%10)*(p/10%10*10+p%10);
p/=10;
r=max(r,p);
l=min(l,p);
return p;
}
int slove(char asc[],int f)//分配哈希函数
{
int ans=0,i;
for(i=0;asc[i];i++)
ans+=asc[i];
switch(f)
{
case 0:return ans;
case 1:return hashnum1(ans);
case 2:return hashnum2(ans);
case 3:return hashnum3(asc);
}
}
/*****以下链地址法解决冲突******/
struct Node
{
char key[20];//名字
struct Node *next;
};
struct Hash
{
int sum;//冲突次数
struct Node *data;//结点
}h[N];
void init()//malloc->free
{
struct Node *q,*p;
for(int i=l;i<=r;i++)
{
h[i].sum=0;
p=h[i].data;
while(p!=NULL)
{
q=(*p).next;
free(p);
p=q;
}
}
for(int i=l;i<=r;i++)
h[i].data=NULL;
l=0x3f3f3f3f,r=0;
}
void inserthash(int k,char asc[])//插入
{
struct Node *q;
q=(struct Node *)malloc(sizeof(struct Node));
strcpy((*q).key,asc);
(*q).next=h[k].data;
h[k].data=q;
h[k].sum++;
}
int searchhash(int k,char asc[])//查找
{
struct Node *p=h[k].data;
int cut=0;
while(p!=NULL)
{
cut++;
if(strcmp(asc,(*p).key)==0)
return cut;
p=(*p).next;
}
return 0;
}
void printff()//打印哈希表
{
printf("哈希表如下所示:\n");
for(int i=l;i<=r;i++)
{
printf("%d",i);
if(h[i].data!=NULL)
{
struct Node *p=h[i].data;
while(p!=NULL)
{
printf(" ->%s",(*p).key);
p=(*p).next;
}
}
printf("\n");
}
}
void chongtu()//平均查找长度
{
int i,k=0;
for(i=1;i<=n;i++)
k+=searchhash(slove(s[i],flag),s[i]);
switch(flag)
{
case 1:
{
printf("您选择的是取余法,平均查找长度为:%.2lf\n",k*1.0/n);
return ;
}
case 2:
{
printf("您选择的是数字分析法,平均查找长度为:%.2lf\n",k*1.0/n);
return ;
}
case 3:
{
printf("您选择的是直接定址法,平均查找长度为:%.2lf\n",k*1.0/n);
}
}
}
/**********************************/
/*****以下开放地址法解决冲突******/
struct ss
{
char name[20];
int length;
int emp;
}H[N];
void init2()//清零
{
memset(H,0,sizeof(H));
l=0x3f3f3f3f,r=0;
}
void inserthash2(int k,char asc[])//插入
{
int cnt=1,p=1;
while(H[k].emp)
{
if(cnt&1)
k=(k+p*p)%r;
else k=(k-p*p)%r,p++;
cnt++;
}
strcpy(H[k].name,asc);
H[k].length=cnt;
H[k].emp=1;
}
int searchhash2(int k,char asc[])//查找
{
int cnt=0,p=1;
while(H[k].emp)
{
cnt++;
if(strcmp(asc,H[k].name)==0)
return cnt;
if(cnt&1)
k=(k+p*p)%r;
else k=(k-p*p)%r,p++;
}
if(!H[k].emp)
return 0;
}
void printff2()//打印哈希表
{
printf("哈希表如下所示:\n");
for(int i=l;i<=r;i++)
{
printf("%d",i);
if(H[i].emp)
printf(" ->%s %d",H[i].name,H[i].length);
printf("\n");
}
}
void chongtu2()//平均查找长度
{
int i,k=0;
for(i=1;i<=n;i++)
k+=searchhash2(slove(s[i],flag),s[i]);
switch(flag)
{
case 1:
{
printf("您选择的是取余法,平均查找长度为:%.2lf\n",k*1.0/n);
return ;
}
case 2:
{
printf("您选择的是数字分析法,平均查找长度为:%.2lf\n",k*1.0/n);
return ;
}
case 3:
{
printf("您选择的是直接定址法,平均查找长度为:%.2lf\n",k*1.0/n);
}
}
}
/*********************************/
int main()
{
int i,j,k,p,v;
printf("请输入姓名:\n");
for(i=1;i<=n;i++)
scnaf("%s",s[i]);
printf("\n请选择冲入处理方式:\n 1.链地址法\n 2.开放定址法\n");
scanf("%d",&v);
if(v&1)
{
printf("\n您选择的是链地址法\n");
printf("\n请选择哈希函数:\n 1.取余法\n 2.数字分析法\n 3.直接定址法\n");
scanf("%d",&flag);
init();
for(i=1;i<=n;i++)
{
k=slove(s[i],flag);
inserthash(k,s[i]);
}
switch(flag)
{
case 1:printf("\n您选择的是取余法\n");break;
case 2:printf("\n您选择的是数字分析法\n");break;
case 3:printf("\n您选择的是直接定址法\n");break;
}
while(1)
{
printf("\n请输入:\n 0.退出\n 1.插入名字\n 2.查找名字\n 3.打印哈希表\n 4.平均查找长度\n");
scnaf("%d",&p);
if(!p)
{
init();
break;
}
switch(p)
{
case 1:
{
printf("\n请输入您要添加的名字:\n");
scnaf("%s",s[++n]);
k=slove(s[n],flag);
inserthash(k,s[n]);
break;
}
case 2:
{
printf("\n请输入您要查找的名字:\n");
scnaf("%s",x);
k=slove(x,flag);
j=searchhash(k,x);
if(!j)
printf("\n查找失败,请重新输入\n");
else printf("\n查找成功,查找长度为:%d\n",j);
break;
}
case 3:printff();break;
case 4:chongtu();break;
}
}
}
else
{
printf("\n您选择的是开放定址法\n");
printf("\n请选择哈希函数:\n 1.取余法\n 2.数字分析法\n 3.直接定址法\n");
scanf("%d",&flag);
init2();
for(i=1;i<=n;i++)
{
k=slove(s[i],flag);
inserthash2(k,s[i]);
}
switch(flag)
{
case 1:printf("\n您选择的是取余法\n");break;
case 2:printf("\n您选择的是数字分析法\n");break;
case 3:printf("\n您选择的是直接定址法\n");break;
}
while(1)
{
printf("\n请输入:\n 0.退出\n 1.插入名字\n 2.查找名字\n 3.打印哈希表\n 4.平均查找长度\n");
scnaf("%d",&p);
if(!p)
{
init2();
break;
}
switch(p)
{
case 1:
{
printf("\n请输入您要添加的名字:\n");
scnaf("%s",s[++n]);
k=slove(s[n],flag);
inserthash2(k,s[n]);
break;
}
case 2:
{
printf("\n请输入您要查找的名字:\n");
scnaf("%s",x);
k=slove(x,flag);
j=searchhash2(k,x);
if(!j)
printf("\n查找失败,请重新输入\n");
else printf("\n查找成功,查找长度为:%d\n",j);
break;
}
case 3:printff2();break;
case 4:chongtu2();break;
}
}
}
return 0;
}
/*
int main()
{
char v[35][20];
int a[35];
for(int i=1;i<=n;i++)
scnaf("%s",v[i]),a[i]=slove(v[i],1);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
printf("%d\n",a[i]);
return 0;
}
/
//29|22-3 31|22-2
/
700~140
yangxinyi
lihaoyu
xuhaidong
songzongzui
wangzongyao
zhangwenqi
liudengtian
huoyuqing
fangyuanyuan
wangweiyi
wangyan
zhoumeichen
chenshuai
hanmeng
liyaran
yuxiaolei
lujiale
shichenghong
liuwanyou
chaiwenli
wanghaozhi
zhaobowen
gaoruiying
lijinfang
sunpeng
sunshanpeng
wanghongyang
xinghaora
qinyichen
xiuyuhang
*/文章来源地址https://www.toymoban.com/news/detail-502832.html
到了这里,关于【数据结构实训】哈希表设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!