哈希(构造哈希函数)

news2024/11/28 14:53:12

哈希

哈希也可以叫散列

画一个哈希表

 

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

闭散列开放定址法:

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;//记录表中存储的数据个数
	};
}

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

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

相关文章

Oracle11g账户频繁被锁定的3种解决办法

方法1&#xff1a;创建触发器 方法1&#xff1a;数据库中创建触发器(只记录失败)&#xff0c;但是需要开发同意或者开发自己创建。找到密码输入错误的服务器&#xff0c;进行数据源配置的更改。 该方法适用于要求找到密码错误用户所在服务器的场景下。 CREATE OR REPLACE TR…

Llama 3 + Groq 是 AI 天堂

我们将为生成式人工智能新闻搜索创建一个后端。我们将使用通过 Groq 的 LPU 提供服务的 Meta 的 Llama-3 8B 模型。 关于Groq 如果您还没有听说过 Groq&#xff0c;那么让我为您介绍一下。 Groq 正在为大型语言模型 (LLM) 中文本生成的推理速度设定新标准。 Groq 提供 LPU&…

kettle经验篇:MongoDB-delete插件问题

目录 项目场景 问题分析 解决方案 MongoDB Delete插件使用总结 项目场景 项目使用的ODS层数据库是MongoDB&#xff1b;在数据中心从DB层向ODS层同步数据过程中&#xff0c;发现有张ODS表在同步过程中&#xff0c;数据突然发生锐减&#xff0c;甚至于该ODS表数据清0。 同步…

dragonbones 5.6.3不能导出的解决办法

问题描述 使用dragonbones 5.6.3导出资源时无反应。 解决方法 第一步安装node.js&#xff0c;我这里使用的是V18.16.0第二步进入到DragonBonesPro\egretlauncher\server\win目录&#xff0c;然后把里面的node.exe替换为刚刚下载的node文件夹即可&#xff0c;如下图&#xff…

GD32用ST-Link出现internal command error的原因及解决方法

一、GD32 F407烧录时出现can not reset target shutting down debug session 搜寻网上资料&#xff0c;发现解决方式多种多样&#xff0c;做一个简单的总结&#xff1a; 1.工程路径包含中文名 2.需更改debug选项 3.引脚冲突 4.杜邦线太长 而先前我的工程路径包含中文名也仍…

Shell编程之循环语句之for

一.for循环语句 读取不同的变量值&#xff0c;用来逐个执行同一组命令 for 变量名 in 取值列表 do命令序列 done 示例&#xff1a; 1.计算从1到100所有整数的和 2.提示用户输入一个小于100的整数&#xff0c;并计算从1到该数之间所有整数的和 3.求从1到100所有整数的偶数和…

【Android】Kotlin学习之Kotlin方法的声明和传参

方法声明 普通类的方法 静态类的方法 不需要构建实例对象, 可以通过类名直接访问静态方法 : NumUtil.double(1) companion object 伴生类的方法 使用companion object 在普通类里定义静态方法 参数 括号内传入方法 : 当参数是方法时, 并且是最后一个参数 , 可以使用括号外…

QX---mini51单片机学习---(8)8*8点阵屏

目录 1LED点阵屏简绍 2 8*8点阵屏电路图74 3 74HC595芯片 4实践编程 1LED点阵屏简绍 2 8*8点阵屏电路图74 怎么点亮&#xff0c;正极给高负极给低 不能同时静态显示&#xff0c;跟数码管动态显示一样&#xff0c;反复横跳&#xff0c;利用视觉效果 3 74HC595芯片 …

涉案财物管理系统|DW-S405系统全国都有案例

涉案财物管理系统&#xff08;智财物&#xff1a;DW-S404&#xff09;是一套成熟系统&#xff0c;依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对涉密载体进行统一管理、分析的信息化、智能化、规范化的系统。 涉案财物管理系统主要实现对涉案物品进…

第三步->手撕spring源码之基于Cglib实现实例化策略

为什么深入研究spring源码&#xff1f; 其实每一个程序员每天的工作都是一贯的CRUD 实现业务和需求完成的操作。几年这样的操作让我感觉在这方面要提神能力 光靠CRUD是绝对不可能的事情 CRUD只是满足你作为一个搬砖人而已。编程能力提升&#xff1f;其实更多的编程能力的提升是…

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

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

事务-MYSQL

目录 1.事务操作演示 2.事务四大特性ACID 3.并发事务问题 4. 并发事务演示及隔离级别​编辑​编辑​编辑​编辑​编辑​编辑​编辑 1.事务操作演示 默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。 方式二 2.事务四大特性ACID 原子…

璩静事件,后生可畏

时下网络上沸沸扬扬的璩静事件&#xff0c;笔者认为这应当是事先策划好的&#xff0c;为她自己的新公司扩大声势的一种炒作方式。聪明而胆大。年轻人&#xff0c;尤其是年轻女性&#xff0c;让人深感“后生可畏”。 来百度APP畅享高清图片 【附件】 《百度副总裁璩静言论引争…

Redis系列-3 Redis缓存问题

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

Electron学习笔记(六)

文章目录 相关笔记笔记说明 七、系统5、托盘图标(1)、设置托盘图标(2)、托盘图标闪烁(3)、托盘图标菜单 6、剪切板(1)、写入剪切板(2)、读取剪切板 7、系统通知8、其他(1)、使用系统默认应用打开文件(2)、接收拖拽到窗口中的文件(3)、使用系统字体 相关笔记 Electron学习笔记&…

异常处理/CC++ 中 assert 断言 应用实践和注意事项

文章目录 概述assert 本质浅析Release版本下的assert是否生效默认设置下 QtCreator环境 assert 过程默认配置下 VS环境 assert 过程配置VS发布模式下的断言生效VS环境Release版本的UI程序Release下请当我不生效 请勿滥用assert导致逻辑错误再强调不要在assert内执行逻辑功能怎敢…

华为交换机配置导出备份python脚本

一、脚本编写思路 &#xff08;一&#xff09;针对设备型号 主要针对华为&#xff08;Huawei&#xff09;和华三&#xff08;H3C&#xff09;交换机设备的配置备份 &#xff08;二&#xff09;导出前预处理 1.在配置导出前&#xff0c;自动打开crt软件或者MobaXterm软件&am…

IEEE 802.11标准

在IEEE 802.11标准中使用了扩频通信技术&#xff0c;主要作用是使得抗干扰性更强。 IEEE 802.11在MAC层采用了CSMA/CA协议。 IEEE 802.1x是一种基于端口认证协议。

【数据分析面试】41.如何分析处理Netflix流失用户?(业务分析)

题目 假设有一百万 Netflix 用户在过去六个月内没有登录到 Netflix。 你会如何确定原因&#xff1f;以及你会如何处理这些用户&#xff1f; Netflix 是一家总部位于美国的全球性流媒体娱乐服务公司&#xff0c;提供在线视频点播服务。通过其网站和移动应用&#xff0c;用户可…

内容检索(2024.05.12)

随着创作数量的增加&#xff0c;博客文章所涉及的内容越来越庞杂&#xff0c;为了更为方便地阅读&#xff0c;后续更新发布的文章将陆续在此汇总并附上原文链接&#xff0c;感兴趣的小伙伴们可持续关注文章发布动态&#xff01; 本期更新内容&#xff1a; 1. 信号仿真类话题-…