Hash哈希表的全新理解

一、Hash哈希表

无论是栈、队列、还是顺序表等线性结构中,记录的关键字和存储位置之间都不存在一 一对应的关系。在查找记录的时候,则需要对关键字进行逐一比对,过程繁琐,查找效率低。
哈希表是一种高效的查找结构,它的出现很好地解决了这个问题,接下来让我们逐步深入学习。

二、哈希函数

哈希函数是哈希表的灵魂,正因为它的存在,哈希表才完成了从记录关键字到存储位置的一一映射关系。类比y=f(x),存储位置作为因变量是由自变量关键字经过某种函数关系计算而得的。

哈希函数的构造方法:

  1. 直接定址法(y=x):不作变换,直接使用关键字作为哈希地址。
  2. 除留余数法(y=x%a,其中a为常数)
  3. 数字分析法:在关键字中选择分布均匀的位数作为哈希地址(这种方法观察主观选择,与函数无关)
  4. 折叠法
  5. 平方取中法

三、冲突以及处理冲突的方法

首先什么叫冲突?
我们都知道想y=x^2,当y=1时方程有两个解1或者-1。可是如果“1”代表的是唯一的存储地址1,那么这时候究竟是存放“1”还是“-1”呢?(冲突,也就这样产生了)
想要解决冲突就是要解决两个解如何存放的问题(一山不能容二虎)。

  • 链地址法:

平时操场集合的时候,前面排列着各个班的班牌(有且只有一个),每个班都不止一位同学,如何大家都站在班牌那,这就发生了冲突,所以该如何站呢?
很简单,以班牌为地址,同班同学在同一列,逐一向后排列即可。

同样的道理,如果我们能在存储地址1的下方放置另一个解“-1”,依此类推,那冲突的问题就解决了。

因此,我们需要创建一个指针数组,指针数组里的每个元素就好像是操场上的班牌一样,指向着整个班,而后,每个记录都采用链表结点的方式,在同一“班牌”下的记录,按先来后到的方式链接在后面。
如图:
在这里插入图片描述

  • 开放地址法:
    既然哈希函数可以实现记录关键字和存储位置的一一对应,那我们直接可以新建一个处理冲突的函数(y=x^2-1或者其他可以改变y的函数),这样子,实现了多个解发生冲突的时候,可以错开存放。
    在这里插入图片描述
    另外,
    根据所选的冲突函数不同,又分为线性探测法二次探测法(y=x^(2) -a ^(2))

四、哈希表的实现

根据不同的处理冲突的方法,哈希表可以分成两类链地址哈希表开放定址哈希表
(本次主要介绍链地址哈希表,下一讲再介绍开放定址哈希表开放定址哈希表的代码详解)

链地址哈希表类型定义:

 typedef struct {
	KeyType key;	//KeyType为新定义类型,方便多种关键字转换 
}RcdType; //记录的结构
typedef struct Node {
	RcdType r;
	struct Node *next;
}Node;	//结点的结构
typedef struct {
	Node **rcd;
	int size;
	int count;
	int (*hash)(KeyType key,int size);//函数指针,可以指向整形,含有两个参数的函数
}Hash;	//哈希表的结构

链地址哈初始化:

//链地址哈希表初始化 
Status InitHash (Hash &H,int size,int (*hash)(int,int)) { //Status 认为定义类型,方便多种类型间转换 
	H.rcd = (Node**)malloc(size*sizeof(Node*));
	if (NULL==H.rcd) {
		return ERROR;
	}
	else {
		for (int i=0;i<size;i++) H.rcd[i] =NULL;	//注意区分H.rcd=NULL;
		H.size = size;
		H.count = ERROR;
		H.hash = hash;
		return ERROR;
	}
}

查找记录:

Node * SearchHash(Hash &H,int key) {
	//使用哈希函数 
	int h = hash(key,H.size);
	Node *p ;
	for (p = H.rcd[h];p!=NULL;p = p->next) {
		if (p->r.key==key) return p;
	}
	return NULL;
}

在表头插入记录:

Status InsertHash (Hash &H,RcdType e) {
	if (SearchHash(H,e.key)==NULL) {
		int h = hash(e.key,H.size);
		Node *p ;
		p->r = e;
		p->next = H.rcd[h];
		H.rcd[h] = p;
		H.count++;		//成功插入后,哈希表内记录数+1;
		return OK;
	} 
	else {
		return FALSE;
	} 
} 

删除记录:

Status  DeleteHash (Hash &H,int key,RcdType &e) {
	Node *p = SearchHash(H,e.key);
	if (p==NULL) {
		return 0; 
	} 
	else {
		key = p->r.key;
		int h = hash(e.key,H.size);
		Node *pr;
		while (pr->next!=p) {
			pr = pr->next;
		}
		pr = p->next;
		free(p);
		H.count--;
		return key;
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱上bug的小姐姐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值