C语言 哈希表设计

一、实验目的

理解哈希表实现机制,掌握哈希函数的构造方法和冲突处理方法,实现哈希表上的查找、插入和删除操作。

二、实验内容

(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);
	}

 

  • 7
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是不是应该好好学习呢?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值