【C++】哈希一

这篇博客要说的是哈希算法哈希又称为散列,它是将存储的和存储的位置建立起关联关系的一种算法,或者说是一种任意长度的数据映射为固定长度的输出的算法

什么意思呢?我们来看一个例子:比如说我们要存储1,2,3,4,5,6这几个数据,我们可以开6个空间大小的数组用于存储,正好下标(位置)跟数据(值)之间是有一定的关系的,很容易存储。

但是假如是下面6个数据呢?1,2,3,1000,1001,1002难道我们还要开1000个空间不成?当然不可以,这太浪费了,于是就开始想办法,让它们都对于总个数6取余不就得到范围比较小的值了吗。它们取余后分别得到1,2,3,4,5,0,我们让这几个数据当作它们各自的位置,这样每一个数据都和一个位置相互对应了,这就是一种解决问题的方法。

上面两个例子已经很形象的说明了什么是哈希,并且第一个例子就是我们的直接定址法,第二个例子就是除留余数法

但是我们的除留余数法还是有问题的,有没有可能两个数取余后得到的数相同?肯定是有可能的,这种情况就叫哈希冲突。我们可以知道,哈希冲突越多,那么效率就越低。所以我们一般当负载因子或者叫载荷因子就是实际存的数据个数除以表的大小)大于某个数就要扩容,增大表的大小。这样就可以一定程度的保证效率。那么接下来我们就要解决哈希冲突,有两种方法,一种叫闭散列开放定址法,一种叫开散列拉链法,也叫哈希桶

它们分别是什么意思呢?下面我们分别来说,闭散列开放定址法就是在这个固定长度的数组中如果一个值要放的位置已经有其他的值了,那么就从这个位置向后边找,直到找到空的位置放入,如果找到结尾,那么再返回头去找。这个向后边找可以一个一个找,就叫线性探测,也可以1,4,9,16.....这样二次方数这样找,就叫做二次探测

下面一个是哈希桶也叫开散列拉链法,就是我们在哈希表中存某个数据所在节点的指针,如果下个数据仍然在这个位置,那么就挂在上个数据的下边就可以了,挂上数据之后就像一个桶或者像拉链,于是名字由此得名

那么接下来我们就分别用这两种解决哈希冲突的方法来实现一下哈希表,这里我们的哈希表中的值先按整形看,等后边我们再慢慢加上模板等一系列东西,先看第一种方法

enum state {
	EMPTY,
	EXIST,
	DELETE
};
struct HashNode {
	int val=0;
	state state=EMPTY;
};
class HashTable {
public:
	HashTable(size_t n = 10) {
		_hashvec.resize(n);
	}
	HashNode* find(size_t key) {
		int hashi = key % _hashvec.size();
		while (_hashvec[hashi].state != EMPTY && _hashvec[hashi].val != key) {
			hashi++;
			hashi %= _hashvec.size();
		}
		if (_hashvec[hashi].state == EMPTY)return nullptr;
		return &_hashvec[hashi];
	}

	bool insert(size_t data) {
		if (find(data))return false;
		if (_n * 10 / _hashvec.size() >= 7) {
			//扩容
			HashTable newtable;
			newtable._hashvec.resize(_hashvec.size()*2);
			for (size_t i = 0; i < _hashvec.size(); i++) {
				if(_hashvec[i].state==EXIST)
				newtable.insert(_hashvec[i].val);
			}
			_hashvec.swap(newtable._hashvec);
		}
		size_t hashi = data % _hashvec.size();
		while (_hashvec[hashi].state == EXIST) {
			hashi++;
			hashi %= _hashvec.size();
		}
		_hashvec[hashi].val = data;
		_hashvec[hashi].state = EXIST;
		_n++;
		return true;
	}
	bool erase(size_t data) {
		HashNode* tmp = find(data);
		if (tmp == nullptr)return false;
		tmp->state = DELETE;
		--_n;
		return true;
	}
private:
	size_t _n=0;
	vector<HashNode> _hashvec;
};

再看第二种方法

struct HashNode {
		HashNode(size_t n=0)
			:val(n)
			,_next(nullptr){}

		size_t val = 0;
		HashNode* _next = nullptr;
	};
	class HashTable {
	public:
		HashTable(size_t n=10) {
			_hashvec.resize(n, nullptr);
		}
		HashNode* find(size_t key) {
			size_t hashi = key % _hashvec.size();
			HashNode* cur = _hashvec[hashi];
			while (cur) {
				if (cur->val == key)return cur;
				cur = cur->_next;
			}
			return nullptr;
		}
		bool insert(size_t key) {
			if (find(key))return false;
			if (_n == _hashvec.size()) {
				//扩容
				HashTable newtable(_hashvec.size() * 2);
				for (size_t i = 0; i < _hashvec.size(); i++) {
					HashNode* cur = _hashvec[i];
					HashNode* next = nullptr;
					while (cur) {
						next = cur->_next;
						size_t hashi = cur->val % newtable._hashvec.size();
						cur->_next = newtable._hashvec[hashi];
						newtable._hashvec[hashi] = cur;

						/*if (newtable._hashvec[hashi] == nullptr) {
							newtable._hashvec[hashi] = cur;
						}
						else {
							HashNode* tmp = newtable._hashvec[hashi];
							while (tmp->_next) {
								tmp = tmp->_next;
							}
							tmp->_next = cur;
						}
						cur->_next = nullptr;*/
						cur = next;
					}
					_hashvec[i] = nullptr;
				}
				_hashvec.swap(newtable._hashvec);
			}
			size_t hashi = key % _hashvec.size();
			HashNode* newnode = new HashNode(key);
			newnode->_next = _hashvec[hashi];
			_hashvec[hashi] = newnode;
			++_n;
			return true;
		}
		bool erase(size_t key) {
			size_t hashi = key % _hashvec.size();
			HashNode* prev = nullptr;
			HashNode* cur = _hashvec[hashi];
			while (cur&&cur->val != key) {
				prev = cur;
				cur = cur->_next;
			}
			if (cur == nullptr)return false;
			if (prev == nullptr) {
				_hashvec[hashi] = cur->_next;
			}
			else {
				prev->_next = cur->_next;
			}
			delete cur;
			return true;
		}
	private:
		size_t _n = 0;
		vector<HashNode*> _hashvec;
	};
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

控制某个对象缩放

效果如下&#xff1a; 您只需要控制此对象进行激活&#xff0c;将对象设置为&#xff1a;gameObject.SetActive(true);即可实现此次效果 代码如下&#xff1a; public class StartShowRun : MonoBehaviour {Transform _localTransfrom;Vector3 _localScale;public AnimationC…

高效可扩展,使用Dask进行大数据分析

大家好&#xff0c;Dask技术作为并行计算领域的创新力量&#xff0c;正在重塑大数据的处理模式。这项开源项目为Python语言带来了强大的并行计算能力&#xff0c;突破了传统数据处理在扩展性和性能上的瓶颈。 本文将介绍Dask的发展历程、架构设计&#xff0c;并分析其在大数据…

Qt中连接mysql

1、安装mysql&#xff0c;workbench&#xff0c;为mysql添加环境变量 2、安装Qt带src&#xff0c;然后到如下目录&#xff0c;找到mysql.pro(建议做个副本先) http://D:\Qt\Qt5.13.2\5.13.2\Src\qtbase\src\plugins\sqldrivers\mysql mysql.pro 注意路径的 \ / 和双引号的使…

算法练习第15天|226.翻转二叉树

226.翻转二叉树 力扣链接https://leetcode.cn/problems/invert-binary-tree/description/ 题目描述&#xff1a; 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&am…

高分二号卫星(GF-2):中国遥感科技的新高度

​高分二号卫星&#xff08;GF-2&#xff09;是中国在高分辨率地球观测领域的重要成就&#xff0c;其引入了先进的成像技术和灵活的数据获取模式&#xff0c;为地球资源监测、环境保护、城市规划等领域提供了强大的数据支持。本文将深入介绍高分二号卫星的技术特点、成像能力以…

软件测试---性能测试

1.常见的性能问题有哪些 如图所示 系统内部以及软件的代码实现 1&#xff0c;资源泄漏&#xff0c;包括内存泄漏。 2&#xff0c;CPU使用率达到100%&#xff0c;系统被锁定等。 3&#xff0c;线程死锁&#xff0c;阻塞等造成系统越来越慢。 4&#xff0c;查询速度慢&#xff0c…

Console口和Telnet功能配置实验

一、基础配置 <Huawei>system-view //进入系统视图 Enter system view, return user view with CtrlZ. [Huawei]undo info-center enable //关闭接口提示 Info: Information center is disabled. [Huawei]sysname AR1 //配置设备名为 R1 [AR1]interface GigabitEthern…

pta L1-027 出租

L1-027 出租 分数 20 全屏浏览 切换布局 作者 陈越 单位 浙江大学 下面是新浪微博上曾经很火的一张图&#xff1a; 一时间网上一片求救声&#xff0c;急问这个怎么破。其实这段代码很简单&#xff0c;index数组就是arr数组的下标&#xff0c;index[0]2 对应 arr[2]1&#x…

steam怎么退款?steam退款教程?简单几步即可轻松实现退款

steam怎么退款&#xff1f;steam退款教程&#xff1f;简单几步即可轻松实现退款 说到steam平台大家肯定不会陌生&#xff0c;随着现代的发展&#xff0c;在steam上进行购买游戏已经成了很普遍的东西&#xff0c;但是许多玩家在购买游戏试完之后发现游戏并不符合自己的胃口&…

transformer上手(9)—— 翻译任务

运用 Transformers 库来完成翻译任务。翻译是典型的序列到序列 (sequence-to-sequence, Seq2Seq) 任务&#xff0c;即对于每一个输入序列都会输出一个对应的序列。翻译在任务形式上与许多其他任务很接近&#xff0c;例如&#xff1a; 文本摘要 (Summarization)&#xff1a;将长…

地质灾害监测预警系统:科技守护,构筑智能预警屏障

随着全球气候变化和人为活动的加剧&#xff0c;地质灾害频繁发生&#xff0c;给人们的生命财产安全带来了严重威胁。为了降低地质灾害带来的损失&#xff0c;地质灾害监测预警系统应运而生。本文将为您详细介绍地质灾害监测预警系统的原理、功能以及在实际应用中的效果。 一、地…

【考研数学】全年各阶段用书汇总+资料分享

我一战备考很迷茫&#xff0c;身边室友也都是&#xff0c;和室友一起去买资料&#xff0c;网上推荐的看到了就都买了 大家都不知道怎么样才能选对数学参考书然后快速进入备考状态&#xff0c;最后犹犹豫豫买了一堆资料都没有正式开始备考... 从小都算是身边人口中“偏科&…

L2-3 完全二叉树的层序遍历

完全二叉树的层序遍历 一个二叉树&#xff0c;如果每一个层的结点数都达到最大值&#xff0c;则这个二叉树就是完美二叉树。对于深度为 D 的&#xff0c;有 N 个结点的二叉树&#xff0c;若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点&#xff0c;这样的树就是完全…

箭头函数有哪些不适用场景

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

预分频器×重装载值)/LSI频率 为什么等于总时间

1. 第一种算法理解&#xff1a;分频系数 64 &#xff0c;外部低速时钟40khz&#xff0c; 则一次计数周期1.6ms &#xff0c;计数625个数&#xff0c;则有625个周期 &#xff0c;1.6ms*625 等于1s 如果分频系数是64&#xff0c;外部低速时钟&#xff08;LSI&#xff09;频率是…

动态规划|416.分割等和子集

力扣题目链接 class Solution { public:bool canPartition(vector<int>& nums) {int sum 0;// dp[i]中的i表示背包内总和// 题目中说&#xff1a;每个数组中的元素不会超过 100&#xff0c;数组的大小不会超过 200// 总和不会大于20000&#xff0c;背包最大只需要其…

STM32标准库+HAL库 | CPU片内FLASH存储器数据掉电读写

一、片内FLASH 在STM32芯片内部有一个FLASH存储器&#xff0c;它主要用于存储代码&#xff0c;我们在电脑上编写好应用程序后&#xff0c;使用下载器把编译后的代码文件烧录到该内部FLASH中&#xff0c; 由于FLASH存储器的内容在掉电后不会丢失&#xff0c;芯片重新上电复位后&…

车载摄像头畸变校正解决方案,打造无畸变高清视界

在车载摄像头日益普及的今天&#xff0c;摄像头图像的畸变问题成为了制约图像质量提升的一大瓶颈。畸变不仅影响画面的美观度&#xff0c;更关键的是它可能导致智能驾驶系统对环境的误判&#xff0c;进而威胁到行车安全。美摄科技凭借其在图像处理领域的深厚实力&#xff0c;推…

双位置继电器RXMD2-1MRK001984 DC220V JOSEF约瑟

系列型号&#xff1a; RXMD2 1MRK 001 984双位置继电器&#xff1b; RXMD2 1MRK 001 985双位置继电器&#xff1b; RXMD2 1MRK 001 986双位置继电器&#xff1b; 用途 该继电器主要用于直流操作的继电保护和自动化回路中作为大容量双稳态元件进行切换和闭锁。 特点 本继电器…

Vue3项目中快速引入ElementUI框架

ElementUI介绍 ElementUI是一个强大的PC端UI组件框架&#xff0c;它不依赖于vue&#xff0c;但是却是当前和vue配合做项目开发的一个比较好的ui框架&#xff0c;其包含了布局&#xff08;layout)&#xff0c;容器&#xff08;container&#xff09;等各类组件&#xff0c;基本上…
最新文章