哈希(构造哈希函数)

哈希

哈希也可以叫散列

画一个哈希表

 

 哈希冲突越多,哈希表效率越低。

闭散列开放定址法:

1.线性探测,依次往后去找下一个空位置。

2.二次探测,按2次方往后找空位置。

#pragma once
#include<vector>
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
template<class K>
struct SetKeyOfT
{
	const K& operator()(const K& key)
	{
		return key;
	}
};
//unordered_set<K>  ->HashTable<K,K>
//unordered_map<K,V>   ->HashTable<K,pair<K,V>>
enum State
{
	EMPTY,
	EXITS,
	DELETE,	
};
template<class T>
struct HashData//解决:该位置原来就是空还是删除后变为了空
{
	T _data;
	State _state;
};
template<class K,class T,class KeyOfT>
class HashTable//冲突了一定是连续的,但是删除会影响查找,所以应该设置状态标志。将T替换为HashData
{
	typedef HashData<T> HashData;
public:
	bool Insert(const T& d)
	{
		KeyOfT koft;
		//负载因子=表中数据/表的大小  衡量哈希表满的程度
		//表越接近满,插入数据越容易冲突,冲突越多,效率越低。
		//哈希表并不是满了才增容,开放定址法中,一般负载因子到了0.7左右就开始增容
		//负载因子越小,冲突概率越低,整体效率越高,但是负载因子越小,浪费的空间越大。
		//所以负载因子一般去折中值
		if (_tables.size()==0||_num*10/_tables.size()>=7)
		{
			//增容
			//1.开二倍大小的新表
			//2.遍历旧表中的数据,确定数据在新表中的映射位置
			//3.释放旧表
			vector<HashData> newtables;
			size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
			newtables.resize(_tables.size() * 2);
			for (size_t i = 0; i < _tables.size(); ++i)
			{
				if (_tables[i]._state == EXITS)
				{
					size_t index = koft(_tables[i]._data % newtables.size());
					while (newtables[index]._state == EXITS)
					{
						++index;
						if (index == _tables.size())
						{
							index = 0;
						}
					}
					newtables[index] = _tables[i];
				}
			}
			_tables.swap(newtables);
		}
		//KeyOfT koft;
		//计算d中的key在表中映射的位置
		size_t index = koft(d) % _tables.size();
		//EXITS就进行探测
		while (_tables[index]._state==EXITS)
		{
			if (koft(_tables[index]._data) == koft(d))
				return false;
			++index;
			if (index == _tables.size())
			{
				index = 0;
			}
		}
		_tables[index]._data = d;
		_tables[index]._state = EXITS;
		_num++;
		return true;
	}
	HashData* Find(const K& key)
	{
		KeyOfT koft;
		//计算d在表中映射的位置
		size_t index = key % _tables.size();
		while (_tables[index]._state != EMPTY)
		{
			if (koft(_tables[index]._data) == key)
			{
				if (_tables[index]._state == EXITS)
					return &_tables[index];
				else if (_tables[index]._state == DELETE)
					return nullptr;
			}
			++index;
			if (index == _tables.size())
			{
				index = 0;
			}
		}
		return nullptr;
	}
	bool Erase(const K& key)
	{
		HashData* ret = Find(key);
		if (ret)
		{
			ret->_state = DELETE;
			--_num;
			return true;
		}
		else
		{
			return false;
		}
	}
private:
	vector<HashData> _tables;
	size_t _num=0;//存了几个有效数据
};

void TestHashTable()
{
	
	HashTable<int, int, SetKeyOfT<int>> ht;
	ht.Insert(4);
	ht.Insert(14);
	ht.Insert(24);
	ht.Insert(5);
	ht.Insert(15);
	ht.Insert(25);
	ht.Insert(6);
	ht.Insert(16);
	

}

更优的实现方法

开散列哈希桶:

namespace OPEN_HASH
{
	template<class T>
	struct HashNode
	{
		T _data;
		HashNode<T>* _next;
	};
	template<class K,class T,class KeyOfT>
	class HashTable
	{
	public:
		typedef HashNode<T>* Node;
		bool Insert(const T& data)
		{
			//1.先查找这个值在不在表中
			KeyOfT koft;
			//如果负载因子等于1,则增容,避免大量的哈希冲突
			if (_tables.size == _num)
			{
				//增容
				//1.开二倍大小的新表
				//2.遍历旧表中的数据,确定数据在新表中的映射位置
				//3.释放旧表
				vector<Node> newtables;
				size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
				newtables.resize(newsize);
				for (size_t i = 0; i < _tables.size(); ++i)
				{
					//将旧表中的结点取下来重新计算在新表中的位置,并插入进去
					Node cur = _tables[i];
					while (cur)
					{
						Node next = cur->_next;
						size_t index = koft(cur->_data) % newtables.size();
						cur->_next = newtables[index];
						newtables[index] = cur;
						cur = next;
					}
					_tables[i] = nullptr;
				}
				_tables[i].swap(newtables);
			}
			//计算数据在表中映射的位置
			size_t index = koft(data) % _tables.size();
			Node cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == koft(data))
					return false;
				else
					cur = cur->next;
			}
			//2.头插到挂的链表中
			Node newnode = new Node(data);
			newnode->next = _tables[index];
			_tables[index] = newnode;
			++_num;
			return true;
		}
		Node* Find(const K& key)
		{
			KeyOfT koft;
			size_t index = key % _tables.size();
			Node cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == key)
				{
					return cur;
				}
				else return cur->_next;
			}
			return nullptr;
		}
		bool Erase(const K& key)
		{
			KeyOfT koft;
			size_t index = key % _tables.size();
			Node prev = nullptr;
			Node cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == key)
				{
					if (prev == nullptr)
						//表示要删的值在一个结点
						_tables[index] = cur->_next;
					else
						prev->_next = cur->_next;
					delete cur;
					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}
			return false;
		}
	private:
		vector<Node> _tables;
		size_t _num=0;//记录表中存储的数据个数
	};
}

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

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

相关文章

基于SpringBoot+Vue的物流管理系统

运行截图 获取方式 Gitee仓库

机器学习(五) ----------决策树算法

目录 1 核心思想 2 决策树算法主要步骤 3 决策树算法的分类 3.1 ID3算法&#xff08;Iterative Dichotomiser 3&#xff09;&#xff1a; 3.1.1 基本步骤 3.1.2 原理 信息增益 3.1.3 注意事项 3.2 C4.5算法&#xff1a; 3.2.1. 信息增益率 计算公式 3.2.2. 构建决策…

Rpcx (一):详解【介绍、基础示例 demo】

一.rpcx介绍 1.1 rpc是什么 远程过程调用的通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。简单地说就是能使应用像调用本地…

服装店会员管理系统结合小程序商城帮你挖掘出潜在客户

在现代社会&#xff0c;随着科技的不断进步和人们消费习惯的变化&#xff0c;传统的服装店已经不再能够满足消费者的需求。为了更好地服务客户&#xff0c;提升销售业绩&#xff0c;许多服装店开始引入会员管理系统&#xff0c;并结合小程序商城&#xff0c;实现线上线下的无缝…

【半夜学习MySQL】表的约束(含主键、唯一键、外键、zerofill、列描述、默认值、空属性详解)

&#x1f3e0;关于专栏&#xff1a;半夜学习MySQL专栏用于记录MySQL数据相关内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 前言空属性默认值列描述zerofill主键主键概述主键删除与追加复合主键 自增长唯一键外键综合案例 前言 上一篇文章中介绍了数…

Android性能:高版本Android关闭硬件加速GPU渲染滑动卡顿掉帧

Android性能&#xff1a;高版本Android关闭硬件加速GPU渲染滑动卡顿掉帧 如果在Androidmanifest.xml配置&#xff1a; <application android:hardwareAccelerated"false" > 或者某个特点View使用代码&#xff1a; myView.setLayerType(View.LAYER_TYPE_SOFT…

带你手撕红黑树! c++实现 带源码

目录 一、概念 二、特性 三、接口实现 1、插入 情况一&#xff1a;p为黑&#xff0c;结束 情况二&#xff1a;p为红 1&#xff09;叔叔存在且为红色 2&#xff09;u不存在/u存在且为黑色 &#xff08;1&#xff09;p在左&#xff0c;u在右 &#xff08;2&#xff09;…

爱分析基于杭州云器Lakehouse实现成本最优的一体化管理,新一代数据平台的建设方式

导读 1.当前&#xff0c;企业在大数据和数据中台建设上取得成果&#xff0c;但数据开发管理仍具挑战性&#xff08;成本、效率、复杂度&#xff09;。 2.随数据平台领域成熟&#xff0c;厂商应结合自身需求&#xff0c;重新思考“基于开源自建数据平台”的重资产模式与“购买…

Windows单机部署RocketMQ5.X并与SpringBoot集成

RocketMQ 5.X下载 《RocketMQ 5.X下载》 下载后&#xff0c;解压缩 修改初始内存 修改runserver.cmd&#xff08;Linux则为runserver.sh&#xff09; 将下面的-Xms2g -Xmx2g -Xmn1g调小 if %JAVA_MAJOR_VERSION% lss 17 (set "JAVA_OPT%JAVA_OPT% -server -Xms2g -X…

传感网应用开发教程--AT指令访问新大陆云平台(ESP8266模块+物联网云+TCP)

实现目标 1、熟悉AT指令 2、熟悉新大陆云平台新建项目 3、具体目标&#xff1a;&#xff08;1&#xff09;注册新大陆云平台&#xff1b;&#xff08;2&#xff09;新建一个联网方案为WIFI的项目&#xff1b;&#xff08;3&#xff09;ESP8266模块&#xff0c;通过AT指令访问…

计算机毕业设计python校园二手交易系统aqj3i-

什么叫三层架构呢&#xff1f;指的是表示层、组件层、数据访问层。组件层是双层架构没有的&#xff0c;它的加入&#xff0c;把复杂的问题分解得更简单、明了&#xff0c;通过组件层&#xff0c;实现控制数据访问层&#xff0c;这样达到功能模块易于管理、易于访问等目的&#…

【python量化交易】qteasy使用教程06——创建自定义因子选股交易策略

创建自定义因子选股策略 使用qteasy创建自定义因子选股交易策略开始前的准备工作本节的目标Alpha选股策略的选股思想计算选股指标用FactorSorter定义Alpha选股策略交易策略的回测结果用GeneralStg定义一个Alpha选股策略回测结果&#xff1a;本节回顾 使用qteasy创建自定义因子选…

【UnityRPG游戏制作】Unity_RPG项目_PureMVC框架应用

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

Redis系列-3 Redis缓存问题

1.缓存的作用 数据库(如Mysql)的持久化特点带来了较低的性能&#xff0c;高并发的场景下&#xff0c;连接池很快被耗尽而出现宕机或DOS&#xff0c;无法继续对外提供服务。相对于数据库的硬盘IO&#xff0c;缓存中间件基于内存进行读写&#xff0c;从而具备较大的吞吐量和高并…

5.10.6 用于乳腺癌超声图像分类的Vision Transformer

医学超声&#xff08;US&#xff09;成像由于其易用性、低成本和安全性已成为乳腺癌成像的主要方式。卷积神经网络&#xff08;CNN&#xff09;有限的局部感受野限制了他们学习全局上下文信息的能力。利用 ViT 对使用不同增强策略的乳房 US 图像进行分类。 卷积神经网络&#…

你知道C++多少——默认成员函数

&#x1f308;个人主页&#xff1a;小新_- &#x1f388;个人座右铭&#xff1a;“成功者不是从不失败的人&#xff0c;而是从不放弃的人&#xff01;”&#x1f388; &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f3c6;所属专栏&#xff1…

Linux中gitlab-runner部署使用备忘

环境&#xff1a; 操作系统:&#xff1a;CentOS8 gitlab版本&#xff1a;13.11.4 查看gitlab-runner版本 可以从https://packages.gitlab.com/app/runner/gitlab-runner/search找到与安装的gitlab版本相近的gitlab-runner版本以及安装命令等信息&#xff0c;我找到与13.11.4相…

网络 | 应用层-websocket协议概述与握手过程解析

背景&#xff1a;这里为了实现消息实时传输决定引入websocket协议。 不管是发送消息还是接收消息&#xff0c;都需要实时传输&#xff0c;张三发给李四&#xff0c;李四立马就能收到&#xff0c;基于HTTP实现是有些困难的。 但轮询方式也带来了一些问题 1、消耗更多系统资源&…

设计模式——模板设计模式(Template Method)

模板设计-base 什么是模板&#xff1f; 举个简单的例子&#xff0c;以AABB的格式&#xff0c;写出一个词语&#xff0c;你可能会想到&#xff0c;明明白白&#xff0c;干干净净等&#xff0c; 这个AABB就是一个模板&#xff0c;对模板心中有了一个清晰的概念之后&#xff0c;…

draw.text((left, top - 15), text,font=font, fill=“green”)

这是一个Python PIL库中的方法&#xff0c;用于在图片上绘制文本。具体来说&#xff0c;它可以在指定的位置绘制指定的文本&#xff0c;并使用指定的字体、颜色等参数进行渲染。其中&#xff0c;left和top是文本绘制的左上角坐标&#xff0c;text是要绘制的文本内容&#xff0c…