一、实验目的
理解哈希表实现机制,掌握哈希函数的构造方法和冲突处理方法,实现哈希表上的查找、插入和删除操作。
二、实验内容
(1)、对于给定20个人的姓名,用除留余数法构造哈希函数,用线性探测再散列法处理冲突,构造哈希表;
(2)、对于给定的一个姓名,在哈希表上进行查找,如果其存在则将其删除,否则将其插入到该哈希表上。
三、实验原理、方法和手段
实现查找的最基本技术是比较,如果能够建立记录的关键字与其存储地址之间的之间对应,然后以0次或尽可能少的比较次数完成查找,将大大提高算法的效率, 这正是哈希表为查找思想的出发点。 对于给定的若干条记录,以关键字为自变量按照某种方式构造Hash函数,对应的函数值作为该记录的存储地址。显然,一般而言,很难构造出单的Hash函数,即存在关键字不同、对应的Hash函数值却相同的现象,称之为冲突,并称这两个关键字为同义词。对于冲突现象,需要采用合适的机制予以解决。 不妨设字母(不分大小写)a~z对应于数值1~26,对于给定的20个姓名作为关键字,将构成每个姓名的首字母对应的数值相加,然后按照除留余数法构造哈希函数, 并用线性探测再散列法处理冲突,完成哈希表的构造。
C语言代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#define NULLKEY -1
#define DELKEY -2
#define MAX_LINE 1024
#define MAXSIZE 50
typedef int KeyType;
typedef struct //哈希表的数据结构
{
KeyType key; //关键字
int count; //探测次数
}HashTable;
void upcopy(char *new1,char *old) //将old所指向的字符串中的大写字母复制到new1中
{
for(;*old != '\0'; old++) //依次扫描原数组里的大写字母
{
if(*old>='A'&&*old<='Z')
{
*(new1++)=*old; //将原数组中的大写字母赋给新数组
}
}
*new1='\0';
}
int *ReadFile(int *keys) //读取文件,并将20个人的姓名转化为关键字
{ int i=0,j=0;
char *old=NULL,*new1=NULL;
char buf[MAX_LINE];
FILE *fp; //文件指针
int num=0;
char temp[5];
if((fp = fopen("C:\\Users\\Dragonborn\\Desktop\\name.txt","r")) == NULL)
{
perror("fail to read");
exit (1) ;
}
while(fgets(buf,MAX_LINE,fp) != NULL) //fgets函数读取到换行符时停止
{
int num = 0;
for(old=buf;*old!='\0';old++) //计算整个字符串有多长
{
num++;
}
old=buf;
printf("%8s",buf);
new1=(char*)malloc(num); //申请空间来存放大写字符串
upcopy(new1,old);
printf("%8s",new1);
for(i=0; *(new1+i) != '\0'; i++)
*(temp + i) = *(new1 + i);
*(temp+ i) = '\0';
keys[j]=toascii(temp[0])+toascii(temp[1]);//将字符转化为ASCII码值
printf("%d\n",keys[j]); //将每个姓名对应的ASCII码值存入keys数组
j++;
}
return keys;
}
int change(char a[]) //将输入的姓名转化为关键字
{
int i,keys,num;
char *new1=NULL,*old=NULL;
char temp[5];
num=strlen(a);
new1=(char*)malloc(num);
old=a;
upcopy(new1,old);
for(i=0; *(new1+i) != '\0'; i++)
*(temp + i) = *(new1 + i);
*(temp+ i) = '\0';
keys=toascii(temp[0])+toascii(temp[1]); //将字符转化为ASCII码值
return keys; //将每个姓名对应的ASCII码值存入keys
}
void InsertHT(HashTable ha[],int m,KeyType k) //m:哈希表的长度 k:关键字
{
int i,adr;
adr=k%29; //除留余数法,取不大于表长的最大素数
if(ha[adr].key==NULLKEY||ha[adr].key==DELKEY)
{
ha[adr].key=k;
ha[adr].count=1;
}
else
{
i=1;
do
{
adr=(adr+1)%m; //处理冲突:线性探测法
i++; //i是探测次数
}while(ha[adr].key!=NULLKEY&&ha[adr].key!=DELKEY);
ha[adr].key=k;
ha[adr].count=i;
}
printf("%8d",ha[adr].key);
printf("%8d",adr);
printf("%8d",ha[adr].count);
printf("\n");
}
void CreateHash(HashTable ha[],int m,KeyType keys[],int n1)//m:哈希表的长度 keys[]:放关键字的数组 n1:关键字个数
{
for(int i=0;i<m;i++) //初始化哈希表
{
ha[i].key=NULLKEY;
ha[i].count=0;
}
for(int i=0;i<n1;i++)
{
InsertHT(ha,m,keys[i]);
}
//return ha;
}
bool DeleteHT(HashTable ha[],int m,KeyType k)
{
int adr;
adr=k%29;
while(ha[adr].key!=NULLKEY&&ha[adr].key!=k)
{
adr=(adr+1)%m;
}
if(ha[adr].key==k)
{
ha[adr].key==DELKEY;
printf("删除成功!");
return true;
}
else
return false;
}
bool SearchHT(HashTable ha[],int m,KeyType k)
{
int i=1,adr;
adr=k%29;
while(ha[adr].key!=NULLKEY&&ha[adr].key!=k)
{
i++;
adr=(adr+1)%m;
}
if(ha[adr].key==k)
{
printf("成功:关键字%d,比较%d次\n",k,i);
return true;
}
else
{
printf("失败:关键字%d,比较%d次\n",k,i);
return false;
}
}
int main()
{
char a[MAXSIZE],b[MAXSIZE];
int keys[MAXSIZE];
int *keyss=ReadFile(keys);
HashTable h;
printf("关键字: 下标: 探测次数: \n");
CreateHash(&h,30,keyss,20);
printf("请输入需要查找的姓名拼音:") ;
gets(a);
int k=change(a);
if(SearchHT(&h,30,k))
DeleteHT(&h,30,k);
else
InsertHT(&h,30,k);
}