数据结构与算法分析学习----散列

散列表的实现常常叫做散列(hashing),它是一种以常数平均插入,删除,查找的技术。但是这些元素间的任何排序信息的操作将不会得到有效的支持。就是每个元素都有一个KEY值,通过这个KEY值找到该元素,由于这个key值有可能是有冲突的,所以是散列最主要的是如何解决冲突问题

1、分离链接法:
如图:
在这里插入图片描述
咋们可以对数据取然后将其存储到对应的表中即可。Hash(X) = X mod 10;这种方法的思路和了链表差不多。

2、开放定址法
分离链接散列算法的缺点是需要指针,由于给新的单元分配地址需要时间,导致算法速度多少有些减慢。开放定址法就是刚开始定义存储空间,如果有冲突的话,那就通过某个规则去查找下一个存储空间。

1)线性空间探测法。
转换规则就是hi(X)=(Hash(X)+F(i)) mod TableSize 且 F(0)=0,就是相当于逐个探测每个单元(必要时可以绕回)查找出一个空单元。比如插入89 18 49 58 69
第一在这里插入图片描述
假设现在之后10个数据空间,第一个数据89取余之后,存在9哪里,第二个数据18取余存在8哪里,第三个数据49,本来应该也是存在9哪里,但是与89冲突了,于是位置+1回到了0位置**(注:由于这里假设空间大小只有10,9位置已经是极限了,在+1就只能是回头寻找了。)**存在0位置,第四个数据58这个数据和18,89,49冲突了,就只能是存在1哪里,第五个数据69同理只能是存在2哪里。

这种方法比较容易使存储的数据聚集在一块位置,这就导致需要查找多次才能找到新单元。效果不是很好。

2)平方探测法。
平方探测是为了消除线性探测的一次聚集问题,公式是i(X)=(Hash(X)+i*i) mod TableSize
定理:表的大小是素数的时候,当表至少有一半是空的时候,总能找到一个新的元素。
疑问:为啥要指定表的大小为素数呢?网上找到一个回答
H( c ) = c % N;
当N取一个合数8的时候。
H( 11100(二进制) ) = H( 28 ) = 4
H( 10100(二进制) ) = H( 20 )= 4
这时候c的二进制第4位(从右向左数)就”失效”了,也就是说,无论第c的4位取什么值,都会导致H( c )的值一样.这时候c的第四位就根本不参与H( c )的运算,这样H( c )就无法完整地反映c的特性,增大了导致冲突的几率.
取其他合数时,都会不同程度的导致c的某些位”失效”,从而在一些常见应用中导致冲突.
但是取质数,基本可以保证c的每一位都参与H( c )的运算,从而在常见应用中减小冲突几率..


在这里插入图片描述
第一数据89,插入了9的位置,第二个数据18插入了8的位置,第三个数据49与89冲突,根据((9+11)%10=0),插入在0的位置,第4个数据58和18和19冲突,那就是((8+22)%10=2),在第2个位置哪里插入,第5个数据69在和89和49冲突了,那就是
((9+2*2)%10=3),在第3个位置哪里。


下来实现一下平方探测法

#include <stdio.h>
#include <malloc.h>
#include <string.h>
struct sl{
	int key;        //散列键值
	char name[10];  //信息
};
typedef struct sl SL;
#define SLSIZE 10
SL *Initsl(int slsize); //建立表
SL *findsl(int key,SL *head);//查找表
void Insertsl(int key,char *name,SL *head);//插入表
void deletesl(int key,SL *head);//删除表

SL *Initsl(int slsize)
{
	SL *A=0;
	if(slsize<0) return NULL;
	A=malloc(slsize*sizeof(SL)); //申请slsize个内存空间
	memset((char *)A,0,slsize*sizeof(SL));//初始化空间,直接填充0
	return A;

}

SL *findsl(int key,SL *head)
{
	int count=0,i=0,cur;
	if(head==0) return 0;
	cur =key%SLSIZE;//求余数,找出初始位置
	i=cur;
	while(1){
		if(head[i].key==key){
			printf("my key=%d name=%s\n",head[i].key,head[i].name);
			return (head+i);//返回找到的地址
		}
		count++;
		i=(cur+count*count)%SLSIZE; //根据查找公式(Hash(X)+i*i) 求出位置
		if(count>SLSIZE) {
			printf("no find\n");
			return 0; //查找不到

		}
	}
	
}

void Insertsl(int key,char *name,SL *head)
{
	int count=0,i=0,cur;
	if(head==0) return;
	cur =key%SLSIZE;//求余数,找出初始位置
	i=cur;
	while(1){
		if(head[i].key==0){
			break;//找到插入的位置了
		}
		count++;
		i=(cur+count*count)%SLSIZE; //根据查找公式(Hash(X)+i*i) 求出位置
		if(count>SLSIZE) {
			printf("no memory\n");
			return ; //没有足够空间
		}
	}
	head[i].key=key;
	strcpy(head[i].name,name);
}

void deletesl(int key,SL *head)
{
	int count=0,i=0,cur;
	if(head==0) return ;
	cur =key%SLSIZE;//求余数,找出初始位置
	i=cur;
	while(1){
		if(head[i].key==key){
			head[i].key=0;
			memset(head[i].name,0,10);
			printf("dele %d ok\n",key);
			return ; 
		}
		count++;
		i=(cur+count*count)%SLSIZE; //根据查找公式(Hash(X)+i*i) 求出位置
		if(count>SLSIZE) { //找不到
			printf("no find\n");
			return ; 
		}
	}
	
}
void main(void)
{
	int i=0;
	SL *mainhead=0;
	mainhead=Initsl(SLSIZE);//初始化表
	Insertsl(89,"I AM 89",mainhead);
	Insertsl(18,"I AM 18",mainhead);
	Insertsl(49,"I AM 49",mainhead);
	Insertsl(58,"I AM 58",mainhead);
	Insertsl(69,"I AM 69",mainhead);
	for(i=0;i<SLSIZE;i++){  //打印出插入的效果
		if(mainhead[i].key!=0){
			printf(" %2d ",mainhead[i].key);
		}

	}
	printf("\n");

	findsl(49,mainhead);
	deletesl(49,mainhead);
	findsl(49,mainhead);
	findsl(89,mainhead);
	free(mainhead);


}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值