数据结构: 哈希桶

目录

1.概念

2.模拟实现

2.1框架

2.2哈希桶结构

2.3相关功能

Modify

--Insert

--Erase

--Find

2.4非整型数据入哈希桶

1.仿函数

2.BKDR哈希


1.概念

具有相同地址的key值归于同一集合中,这个集合称为一个桶,各个桶的元素通过单链表链接

2.模拟实现

2.1框架

a.写出哈希桶的结构: hash_node  + hash_table     节点  +   指针数组

b.思路: 增删查改的实现 + 扩容  

c.使用除留余数法获得在哈希表中的位置~~>将非整型数据转换为整型数据~~>提供仿函数

2.2哈希桶结构

哈希桶本质是一个指针数组,里面存放的是指针,指向一个链表~~>使用vector来存放  +  n(负载因子)

namespace HashBucket 
{
	//1.节点
	template<class T>
	struct HashNode 
	{
		HashNode<T>* _next;
		T _data;
		//构造函数
		HashNode(const T& data)
			:_next(nullptr)
			,_data(data)
		{}
	};

	//2.哈希表
	template<class T>
	class HashTable 
	{
		typedef HashNode<T> Node;
	public:
		//接口
	private:
		vector<Node>* _tables;
		size_t n = 0; //有效数据个数
	};
}

2.3相关功能

Modify

--Insert

思路:

1.判断是否需要扩容

        a.扩容~~>将原来的数据移动到新开辟的空间

        b.不扩容~~>直接头插

2.头插

        a.计算这个值在哈希表中的位置

        b.单链表的头插

        c.更新hash_table

--将旧数据移动到新开辟的空间

方式1:复用insert~~>额外开辟新节点 + 释放旧的空间

方式2:直接挪动

        a.开辟新空间(创建新表)

        b.遍历原链表~~>取节点下来头插(保存下一个节点 + 重新计算hashi + 头插)

        c.交换新旧表

        

--单链表的头插:

代码:

		bool Insert(const T& data) 
		{
			//1.扩容检查
			if (n == _tables.size()) 
			{
				size_t newsize = _tables.size() == 0 ? 10 : 2 & _tables.size();
				vector<Node*> newtables(newsize, nullptr);	//创建新表
				//将原来的数据挪动到新表
				for (auto& cur : _tables) 
				{
					while (cur) 
					{
						//保存下一个节点
						Node* next = cur->_next;
						//重新计算在哈希桶中的位置
						size_t hashi = (cur->_data) % newtables.size();
						//放进新桶
						cur->_next = newtables[hashi];
						newtables[hashi] = cur;
						cur = next;
					}
				}
				//交换
				_tables.swap(newtables);
			}

			//2.头插数据
			Node* newnode = new Node(data);      //创建节点
			size_t hashi = data % _tables.size();//计算在在个哈希桶
			newnode->_next = _tables[hashi];	 
			_tables[hashi] = newnode;
			++n;

			return true;
		}

效果:

           

--Erase

思路:

1.计算data在哪个哈希桶

2.删除节点

        a.头删~~>更新头

        b.非头删除~~>找pre链接next

代码:

		bool Erase(const T& data) 
		{
			//1.计算在哪个哈希桶
			size_t hashi = data % _tables.size();
			//2.删除节点
			Node* pre = nullptr, * cur = _tables[hashi];
			while (cur) 
			{
				//记录下一个节点
				Node* next = cur->_next;
				if (cur->_data == data) 
				{
					//头删
					if (pre == nullptr) 
					{
						delete cur; cur = nullptr;
						_tables[hashi] = next;
						return true;
					}
					//非头删
					else 
					{
						pre->_next = next;
						delete cur; cur = nullptr;
						return true;
					}
				}
				//没找到继续往后找
				pre = cur;
				cur = cur->_next;
			}
			return false;
		}

效果

--非头删:

--头删

--Find

思路:

如果哈希表没有元素,直接返回

1.计算在哪个哈希桶

2.遍历这个哈希桶,看有没有这个值

代码:

		Node* Find(const T& data) 
		{
			//如果这个哈希表为空, 直接返回
			if (_tables.size() == 0)return nullptr;

			//1.计算在哪个哈希桶
			size_t hashi = data % _tables.size();
			//2.遍历这个桶,找data
			Node* cur = _tables[hashi];
			while (cur) 
			{
				if (cur->_data == data)
					return cur;
				cur = cur->_next;
			}
			//遍历完都没有找到
			return nullptr;
		}

效果:

2.4非整型数据入哈希桶

由于哈希桶是采用除留余数法 ~~>  算在哪个哈希桶 ~~> 必须是整型数据

1.仿函数

使用仿函数将非整型数据转换为整型

代码:

	//仿函数
	template<class T>
	struct HashFunc 
	{
		size_t operator()(const T& data) 
		{
			return data;
		}
	};

2.BKDR哈希

若数据类型是string, "abc" 与"cba"通过相同的哈希函数计算出来的hashi,会相同

~~>引入BKDR哈希, 每次算一个字符的时候, hash *= 31 ~~>让计算出来的hashi尽可能不同

代码:

	//模板特化
	template<>
	struct HashFunc<string> 
	{
		size_t operator()(const string& s) 
		{
			size_t hash = 0;
			for (auto ch : s) 
			{
				hash += ch;
				hash *= 31;
			}
			return hash;
		}
	};

效果:

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

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

相关文章

H5横屏适配方案

横屏模式一般使用场景比较少&#xff0c;特殊情况除外&#xff0c;一般用于游戏、操作性比较大的网页会采用横屏 整体代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" conte…

【第2章 Node.js基础】2.2 Node.js回调函数

学习目标 &#xff08;1&#xff09;理解Node.js的回调函数&#xff1b; &#xff08;2&#xff09;掌握回调函数的使用。 什么是回调函数 回调函数是一种特殊的函数&#xff0c;它作为参数传递给另一个函数&#xff0c;并在特定的事件或条件发生时被调用。回调函数通常用于异…

【Git】深入了解Git及其常用命令

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Git的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Git是什么 二.SVN和Git的区别 三.Git的…

二十、泛型(5)

本章概要 边界通配符 编译器有多聪明逆变无界通配符捕获转换 边界 边界&#xff08;bounds&#xff09;在本章的前面进行了简要介绍。边界允许我们对泛型使用的参数类型施加约束。尽管这可以强制执行有关应用了泛型类型的规则&#xff0c;但潜在的更重要的效果是我们可以在…

【C++】开源:rapidjson数据解析库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍rapidjson数据解析库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

VS Code+DevChat助力非专业开发也能玩转代码编程

一、前言 偶然间网上瞎逛&#xff0c;看到DevChat 发布了一款 VS Code 插件&#xff0c;可提供类似chatgpt一样的“一站式 AI 辅助编程”体验。据说&#xff0c; DevChat 直接对接 GPT-4 还让免费用&#xff0c;目前免费注册收邮件即可获取key&#xff0c;再也不用麻烦的外部手…

web3 从redux中拿出所有已完成订单 并渲染到对应的Table列表中

上文web3 React dapp项目通过事件从区块链中拿到 已取消 已完成 和所有的订单数据 并存入redux中 中 我们已经从 区块中拿到了自己的订单 然后 我们恢复一下上文的环境 ganache ganache -d然后 登一下 MetaMask 然后 用我们的项目 发布一下合约 truffle migrate --reset然后…

使用Streamlit创建AutoGen用户界面

AutoGen作为一个最大化LLM(如GPT-4)能力的框架而脱颖而出。由微软研究院开发的AutoGen通过提供一种自动化、优化和编排工作流的方法&#xff0c;简化了复杂的、基于多代理llm的应用程序的创建。我们在以前的文章中也有过介绍&#xff0c;你可以与许多GPT交谈&#xff0c;并且GP…

STM32独立看门狗(IWDG)溢出时间计算

什么是IWDG&#xff1f; 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动&#xff0c;即使主时钟发生故障它也仍然有效。 IWDG最适合应用于那些需要看门狗作为一个在主程序之外&#xff0c;能够完全独立工作&#xff0c;并且对时间精度要求较低的场合。 从上图我们可以看出IWDG的时…

每日一练 | 华为认证真题练习Day127

1、如图所示&#xff0c;关于OSPF的拓扑和配置&#xff0c;下列说法中正确的是&#xff08;&#xff09;。 A. R1与R2相比&#xff0c;R2更有机会成为DR&#xff0c;因为它的接口DR优先级值较小 B. 只要把R1的接口网络类型恢复为默认的广播类型&#xff0c;R1和R2即可建立稳定…

Netty入门指南之NIO 粘包与半包

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言问题产…

xcode SDK does not contain ‘libarclite‘

SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a; try increasing the minimum deployment target解决方法 iOS13以上

多语言翻译软件 Mate Translate mac中文版特色功能

Mate Translate for Mac是一款多语言翻译软件&#xff0c;Mate Translate mac可以帮你翻译超过100种语言的单词和短语&#xff0c;使用文本到语音转换&#xff0c;并浏览历史上已经完成的翻译。你还可以使用Control S在弹出窗口中快速交换语言。 Mate Translate Mac版特色功能…

由于flutter_app依赖于flutter_swiper>=0.0.2,不支持零安全,版本解决失败。

参考 dart3.0使用flutter_swiper报错记录 flutter_swiper package - All Versions从官网的信息可以看到 Dart3版本不兼容 最小兼容的Dart SDK版本需要2.0 Flutter SDK 版本列表Flutter SDK 版本列表 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 说明&#xff1a;因…

骨传导运动蓝牙耳机推荐,这五款骨传导耳机不要错过!

骨传导耳机在这两年在运动圈中非常火热&#xff0c;相比传统耳机&#xff0c;骨传导耳机使用时开放双耳&#xff0c;不堵塞耳朵&#xff0c;解决了入耳式耳机佩戴的不适感。同时&#xff0c;也避免了戴耳机运动时耳内出汗带来的一系列卫生和健康问题。最关键的是通过耳骨传声&a…

汽车标定技术(八)--MPC57xx是如何支持标定的页切换

目录 1.页切换的概念 1.1 标定常量的理解 1.2 页切换 2.MPC57xx的Overlay模块 3.小结 1.页切换的概念 在汽车标定测量中&#xff0c;有一个概念我想很多人都听过&#xff0c;但是实际上在项目里没有用到过&#xff0c;那就是今天要讲的页切换概念。在讲页切换的时候&#…

高防CDN与高防服务器:谁更胜一筹?

在当今数字化世界中&#xff0c;网络安全对于保护网站和应用程序至关重要。在这一背景下&#xff0c;高防CDN和高防服务器是两种流行的解决方案&#xff0c;用于应对不同类型的网络攻击。本文将分析高防CDN是否能够替代高防服务器&#xff0c;以及它们各自的优势和限制。 高防C…

海思SD3403/SS928开发板 开发记录二: 设置网络 telnet连接开发板

1.设置网络 设置桥接网络 并修改虚拟机IP网段 问题1.参照前一篇博客 2.ping 测试 主机 虚拟机 板端 相互通信 3.telnet 登录板端

《泰山众筹火爆全网,小额投资也能成就泰山伟业》

众筹模式好做吗&#xff1f;我们可以看到电商行业内最先吃螃蟹的那几个众筹平台结局都不大体面。不是平台操盘手被抓&#xff0c;就是平台崩盘&#xff0c;总之&#xff0c;传统的众筹卖货模式的风险性已经深植人心。 众筹卖货真就那么难玩吗&#xff1f;其实并非如此&#xff…

RFID电力资产全周期智能化管理应用解决方案

电力行业需求 国家电网提出了建设“泛在电力物联网”的计划&#xff0c;旨在利用现代信息技术和先进通信技术&#xff0c;实现电力系统各环节的万物互联&#xff0c;构建一个具备全面感知、高效处理和便捷灵活特征的智慧服务系统&#xff0c;其中&#xff0c;重点方向之一是围…