【数据结构】哈希表上——开放寻址法

news2024/9/20 12:08:44

文章目录

  • 前言
  • 映射
  • 哈希冲突
  • 开放寻址法
    • 思路分析
    • 结构分析
    • 函数实现
      • 插入
      • 删除
      • 寻找
  • 结语

前言

大家好久不见,今天来讲解一下哈希表的基本原理并使用开放寻址法实现简单哈希表。

映射

哈希表的实现思路就是将一组数据映射成另外一组可以直接查找的数据,假如有一组数据

10,11,17,13 ,18

我们可以将这些数据通过一定的映射规则映射到一个数组里:
假如数组只有五个元素,我们可以采用 key % 5 的方式寻找映射。

在这里插入图片描述
当我们寻找这个数的时候就按照同样的方式直接在数组下索引即可,这就是哈希的思想,可以大大提高查找的速度。

哈希冲突

通过上面的例子,五个元素的数组并没有装满,18和11都占用了同一个坑位,这种现象叫做哈希冲突,根据映射法则,哈希冲突是必然会出现的,因此我们要设法解决这种冲突。

开放寻址法

解决哈希冲突的第一种方法,开放寻址法的解决方案是线性探测,即如果一个映射的坑位被占,就将这个数据向后放,这种方法代码实现比较简单,但容易发生踩踏,如图:

在这里插入图片描述

假如18因为与13哈希冲突,我们按照线性探测将她放在4的坑位上,当我们要放16的时候,本应放在4号坑位上却因为踩踏智能放在0号位,这样的方式其实并不理想。

简单实现(只实现哈希表,后面会使用链地址法封装unmap系列):

思路分析

开放寻址法即如果被映射的位置已经有了元素,我们就向后寻找第一个没有元素的位置,这里需要注意由于这个向后寻找元素的特点,删除一个元素,我们就不能单纯的置空,否则就有可能找不到元素。

结构分析

通过上面分析,我们需要三个状态表示每个节点的状态,这里采用枚举的方式来实现:

enum States
{
	EXIST,
	DELETE,
	EMPTY
};

那么每一个哈希节点就要至少包含两个元素:
1、数据
2、状态

template<class K,class V>
struct HashDate
{
	pair<K, V> _kv;
	States _st;
};

我们可以用一个存放哈希表节点的数组构造这个哈希表。同时需要一个_n充当负载因子,表示哈希表占用的情况。

template<class K,class V>
class HashTable
{
public:

private:
	vector<HashDate<K, V>> _tables;
	size_t _n = 0;
};

函数实现

插入

插入操作中,有几个细节需要注意:
1、扩容,因为哈希表扩容后对应的映射会更改(size会变),需要重新映射,因此和插入的主逻辑是一致的,我们可以采用开一个新vector,复用insert的逻辑,最后交换两个表即可。
2、线性探测,在探测的时候如果走到数组的最后,需要修正到起点

bool insert(const pair<K,V> kv)
{
	if (find(kv.first)) return false;

	//Expansion
	if (_tables.size() == 0 || _n*10 / _tables.size() > 7)
	{
		size_t newsize = _tables.size() == 0 ? 10 : 2 * _tables.size();

		HashTable<K, V> newht;
		newht._tables.resize(newsize);

		for (auto data : _tables)
		{
			if (data._st == EXIST)
			{
				newht.insert(data._kv);
			}
		}
		//swap(_tables, newht._tables);
		_tables.swap(newht._tables);
	}

	//Insert
	size_t hashi = kv.first % _tables.size();

	//check
	size_t i = 1;
	size_t index = hashi;
	while (_tables[index]._st == EXIST)
	{
		index = hashi + i;
		++i;

		index %= _tables.size();
	}

	_tables[index]._kv = kv;
	_tables[index]._st = EXIST;
	_n++;

	return true;

}

删除

通过key我们找到要删除节点的指针,通过修改他的状态为DELETE表示这个节点已经被删除了,这里也要说明一下如果设置为了EMPTY,下一个数据在线性探测的时候就可能找不到,这也是为什么我们需要设置三个节点状态。

bool erase(const K& key)
{
	HashDate<K, V>* ret = find(key);
	if (ret)
	{
		ret->_st = DELETE;
		_n--;
		return true;
	}

	return flase;
}

寻找

上面的两个操作都使用到了find寻找操作,其实在这种实现方式里,寻找操作也比较简单,我们只需要计算出key,接着向后面进行线性探测即可。

HashDate<K, V>* find(const K& key)
{
	if (_tables.size() == 0) return false;

	size_t hashi = key % _tables.size();

	//线性探测
	size_t i = 1;
	size_t index = hashi;
	while (_tables[index]._st != EMPTY)
	{
		if (_tables[index]._st == EXIST &&
			_tables[index]._kv.first == key)
		{
			return &(_tables[index]);
		}

		index = hashi + i;
		i++;

		index %= _tables.size();

		if (index == hashi)
		{
			break;
		}
	}

	return nullptr;
}

结语

开放寻址法代码比较简单,但很容易发生踩踏事件,这也导致他不如 另一种方法——链地址法常用,下一篇文章我会着重讲解链地址法,同时用其实现unordered_map和unordered_set的封装。
我们下次再见~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/536498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【LeetCode】每日一题:链表部分经典题型

文章目录 1.反转链表2.链表的中间节点3.合并两个有序链表4.相交链表5.环形链表6.环形链表Ⅱ ​&#x1f47b;内容专栏&#xff1a;《LeetCode刷题专栏》 &#x1f428;本文概括&#xff1a;归纳链表部分经典题型。206.反转链表、876.链表的中间节点、21.合并两个有序链表、160.…

如何优雅地彻底解决 antd 全局样式问题

背景 由于某些原因&#xff0c;我们团队负责在组件 上做二次开发&#xff0c;简单理解就是封装组件&#xff0c;组件库选择了 antd&#xff0c;尴尬的是引入之后发现&#xff0c;父组件 自身是带一套全局样式的&#xff0c;而 子组件antd 又带了一套全局样式&#xff0c;导致 子…

字节原来这么容易进,是面试官放水,还是公司实在是太缺人?

本人211非科班&#xff0c;之前在字节和腾讯实习过&#xff0c;这次其实没抱着什么特别大的希望投递&#xff0c;没想到字节可以再给我一次机会&#xff0c;还是挺开心的。 本来以为有个机会就不错啦&#xff01;没想到能成功上岸&#xff0c;在这里要特别感谢帮我内推的同学&…

《程序员面试金典(第6版)》面试题 16.24. 数对和

题目描述 设计一个算法&#xff0c;找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。 题目传送门 示例 1: 输入: nums [5,6,5], target 11 输出: [[5,6]]示例 2: 输入: nums [5,6,5,6], target 11 输出: [[5,6],[5,6]]提示&#xff1a; nums.length &…

基于物联感知和GNSS技术的铁塔安全监测解决方案

监测背景 电力铁塔是承载电力供应的重要设施&#xff0c;它的安全性需要得到可靠的保障。但是铁塔一般安装在户外&#xff0c;分布广泛&#xff0c;且有很多安装在偏远地区&#xff0c;容易受到自然、人力的影响和破环。因此需要使用辅助的方法实时监控通信塔的安全状态&#x…

5th-Generation Mobile Communication Technology(二)

目录 一、5G/NR 1、 快速参考&#xff08;Quick Reference&#xff09; 2、5G Success 3、5G Challenges 4、Qualcomm Videos 二、PHY and Protocol 1、Frame Structure 2、Numerology 3、Waveform 4、Frequency Band 5、BWP 6、Synchronization 7、Beam Management 8、CSI Fra…

一文4000字从0到1用WebDriver+Selenium实现浏览器自动化

前言 Selenium是一款可以自动化操作浏览器的开源项目&#xff0c;最初的目的是浏览器功能的自动化测试&#xff0c;但是随着项目的发展&#xff0c;人们根据它的特性也用来做一些更多的有意思的功能而不仅仅是UI的自动化测试工具。就像Selenium官方网站上描述的那样&#xff0…

chatgpt怎么搭建,以及怎么接入企业微信工作台

gpt目前也用了一段时间了&#xff0c;用起来只能说越来越顺手&#xff0c;然后集成到企业微信让公司全部成员都用起来了。 使用界面如下&#xff1a; 主界面 功能&#xff1a; 1、通过企业微信认证后访问使用&#xff0c;防止非公司人员入侵 2、记录用户姓名和提问内容&#x…

IOS证书制作教程

转载&#xff1a;IOS证书制作教程 点击苹果证书 按钮 点击新增 输入证书密码&#xff0c;名称 这个密码不是账号密码&#xff0c;而是一个保护证书的密码&#xff0c;是p12文件的密码&#xff0c;此密码设置后没有其他地方可以找到&#xff0c;忘记了只能删除证书重新制作&am…

05-函数

函数的定义 函数名 函数名的后面有个圆换号()&#xff0c;代表这个为函数&#xff0c;不是普通的变量名。 形参 在定义函数时指定的形参&#xff0c;在未出现函数调用时&#xff0c;它们并不占内存中的存储单元&#xff0c;因此称它们是形式参数或虚拟参数&#xff0c;简称…

.Net6 使用aspose.cells23.5.0

一、测试代码 internal class Program { static void Main(string[] args) { WorkbookDesigner wb new WorkbookDesigner(new Workbook()); var style new CellsFactory().CreateStyle(); style.Borders.SetColor(C…

LED显示屏控制系统分类

LED显示屏的控制系统可以根据不同的特点和功能进行分类。以下是常见的LED显示屏控制系统分类&#xff1a; 同步控制系统&#xff1a;同步控制系统通过传输同步信号来控制LED显示屏&#xff0c;确保多个显示屏之间的内容同步显示。同步控制系统适用于大型LED显示屏&#xff0c;如…

通过chatGPT学习:kubernetes中的list-watch机制介绍

1、 请解释一下&#xff0c;在kubernetes中的list-watch机制&#xff1f; Kubernetes是一个开源的容器编排和管理系统&#xff0c;它可以有效地管理大规模的容器化应用程序。 在Kubernetes中&#xff0c;list-watch机制是一种重要的机制&#xff0c;用于监视资源的变化并及时…

k8s系列(六)——Service服务发现

Service概述 为什么要使用Service Kubernetes Pod是平凡的&#xff0c;由Deployment等控制器管理的Pod对象都是有生命周期的&#xff0c;它们会被创建&#xff0c;也会意外挂掉。虽然它们可以由控制器自动重建或者滚动更新&#xff0c;但是重建或更新之后的Pod对象的IP地址等都…

什么是单点登录

一、什么是单点登录&#xff1f; 单点登录的英文名叫做&#xff1a;Single Sign On&#xff08;简称SSO&#xff09;。 在初学/以前的时候&#xff0c;一般我们就单系统&#xff0c;所有的功能都在同一个系统上。 后来&#xff0c;我们为了合理利用资源和降低耦合性&#xff…

SmartKnob移植ESP32和STM32

目录 说明一、SmartKnob简介二、SmartKnob移植ESP322.1、电机部分2.2、增加LED和按键2.2.1、LED闪烁2.2.2、按键2.2.2.1、应变片方案2.2.2.2、MT6701方案2.2.2.3、实体按键 2.3、增加氛围灯2.3.1、WS28122.3.2、FastLED 库2.3.3、Freenove_WS2812_Lib_for_ESP32 库 三、SmartKn…

[ACTF新生赛2020]fungame 题解

开辟了一块内存空间&#xff0c;然后有两个函数&#xff0c;进入第一个跟一下 将输入的字符串进行异或&#xff0c;后比较&#xff0c; 解一下 y1[0x23,0x61,0x3e,0x69,0x54,0x41,0x18,0x4d,0x6e,0x3b,0x65,0x53,0x30,0x79,0x45,0x5b] y2[0x71,0x04,0x61,0x58,0x27,0x1e,0x4b,…

vue项目中main.js使用方法详解

目录 一、main.js文件解析 二、Vue.prototype的作用与使用 三、Vue.use的作用以及什么时候使用 1、组件 World 组件 2、定义一个index.js文件&#xff0c;并引入 两组件 &#xff0c;并导出&#xff1a; 3、在 main.js 中引入index.js 4、全局使用(不用引入直接可以使用…

ESD静电监控仪如何提示设备阻值异常

在电子厂的生产过程中&#xff0c;静电是一个不可避免的问题。静电的存在会给电子产品的生产带来很多危害&#xff0c;因此&#xff0c;防静电措施是必不可少的。静电会对电子元器件的性能产生影响。电子元器件对静电非常敏感&#xff0c;即使是微小的静电电荷也可能会对元器件…

功能测试的6中方法你知道多少

对于测试人员而言&#xff0c;软件产品每个按钮的功能是否准确&#xff0c;链接是否能正常跳转&#xff0c;搜索时会不会出现页面错误&#xff0c;验证并减少这些软件使用过程中可能出现的各种小问题都是功能测试的内容。而对于用户而言&#xff0c;功能能否正常执行都是非常直…