unordered_set和unordered_map

news2024/11/17 3:07:13

用哈希结构封装map和set

哈希表的改造

节点

数据类型改为模板
在这里插入图片描述

迭代器

成员

一个节点的指针,哈希表和下标用来++访问,哈希表需要支持修改,传入指针,const为了常迭代器可以传递哈希表
在这里插入图片描述

++

当前节点的next有内容,先遍历完当前桶。否则下标++,寻找下一个不为空的桶

self& operator++()
{
	if (_node->_next)
	{
		//单个桶
		_node = _node->_next;
	}
	else
	{
		
		//下一个桶
		_hashi++;
		while (_hashi < _pht->_table.size())
		{
			if (_pht->_table[_hashi])
			{
				_node = _pht->_table[_hashi];
				break;
			}
			_hashi++;
		}

		//循环结束没有数据
		if (_hashi == _pht->_table.size())
		{
			_node = nullptr;
		}
	}

	return *this;
}

迭代器需要访问哈希表,带上友元
在这里插入图片描述begin返回第一个不为空的桶,end返回空
在这里插入图片描述在这里插入图片描述

凡是数据比较的地方都需要用仿函数
在这里插入图片描述

在这里插入图片描述

#pragma once
#pragma once
#include <string>
#include <iostream>
#include <vector>

template <class T>
struct HashNode
{
	HashNode<T>* _next;
	T _data;

	HashNode(const T& data)
		:_data(data), _next(nullptr)
	{}
};

//hash int
template <class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

//字符串模板特化,string
template <>
struct HashFunc<std::string>
{
	size_t operator()(const std::string& key)
	{
		//BKDR方法
		size_t hash = 0;
		for (auto ch : key)
		{
			hash *= 31;
			hash += ch;
		}

		return hash;
	}
};

//前置声明
template <class K, class T, class KeyOfT, class Hash>
class HashBucket;

template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct __HashIterator
{
	typedef HashNode<T> node;
	typedef __HashIterator<K, T, Ref, Ptr, KeyOfT, Hash> self;

	node* _node;
	const HashBucket<K, T, KeyOfT, Hash>* _pht;
	size_t _hashi;

	__HashIterator(node* node, HashBucket<K, T, KeyOfT, Hash>* pht, size_t hashi)
		:_node(node), _pht(pht), _hashi(hashi)
	{}

	__HashIterator(node* node, const HashBucket<K, T, KeyOfT, Hash>* pht, size_t hashi)
		:_node(node), _pht(pht), _hashi(hashi)
	{}
	
	bool operator!=(const self& x)
	{
		return _node != x._node;
	}

	Ref operator*()
	{
		return _node->_data;
	}

	Ptr operator->()
	{
		return &_node->_data;
	}

	self& operator++()
	{
		if (_node->_next)
		{
			//单个桶
			_node = _node->_next;
		}
		else
		{
			
			//下一个桶
			_hashi++;
			while (_hashi < _pht->_table.size())
			{
				if (_pht->_table[_hashi])
				{
					_node = _pht->_table[_hashi];
					break;
				}
				_hashi++;
			}

			//循环结束没有数据
			if (_hashi == _pht->_table.size())
			{
				_node = nullptr;
			}
		}

		return *this;
	}
};

//unordered_set hashpackage<K, K>
//unordered_set hashpackage<K, pair<K ,V>>

//keyoft取出插入数据的key,hash将其他类型转为整形
template <class K, class T, class KeyOfT, class Hash>
class HashBucket
{
	typedef HashNode<T> node;
	//typedef __HashIterator<K, T, KeyOfT, Hash, const T&, const T*> const_iterator;
	template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
	friend struct __HashIterator;
public:
	typedef __HashIterator<K, T, T&, T*, KeyOfT, Hash> iterator;
	typedef __HashIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;
	
	iterator begin()
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				return iterator(_table[i], this, i);
			}
		}

		//如果都为空
		return end();
	}

	iterator end()
	{
		return iterator(nullptr, this, -1);
	}

	const_iterator begin() const
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				return const_iterator(_table[i], this, i);
			}
		}	
	}
	//const修饰this,传入const HashBucket对象
	const_iterator end() const
	{
		return const_iterator(nullptr, this, -1);
	}

public:
	HashBucket()
	{
		_table.resize(10);
	}

	std::pair<iterator, bool> insert(const T& data)
	{
		KeyOfT kot;
		iterator it = find(kot(data));
		if (it != end())
		{
			return std::make_pair(it, false);
		}
		
		Hash hf;
		//负载因子,1
		if (_n == _table.size())
		{
			//扩容
			size_t newsize = _table.size() * 2;
			std::vector<node*> newtable;
			newtable.resize(newsize, nullptr);
			//遍历旧表
			for (size_t i = 0; i < _table.size(); i++)
			{
				node* cur = _table[i];
				while (cur)
				{
					node* next = cur->_next;
					//挪动到新表
					size_t hashi = hf(kot(cur->_data)) % newtable.size();
					cur->_next = newtable[hashi];
					newtable[hashi] = cur;

					cur = next;
				}
				//旧表还指向节点,置空
				_table[i] = nullptr;
			}

			_table.swap(newtable);
		}

		//Hash hf;
		size_t hashi = hf(kot(data)) % _table.size();
		node* newnode = new node(data);
		//头插
		newnode->_next = _table[hashi];
		_table[hashi] = newnode;

		_n++;

		return std::make_pair(iterator(newnode, this, hashi), true);
	}

	iterator find(const K& key)
	{
		KeyOfT kot;
		Hash hf;
		//线性探测,字符串需要转整数
		size_t hashi = hf(key) % _table.size();
		node* cur = _table[hashi];
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				return iterator(cur, this, hashi);
			}
			cur = cur->_next;
		}

		return end();
	}

	bool erase(const K& key)
	{
		KeyOfT kot;
		Hash hf;
		size_t hashi = hf(key) % _table.size();
		node* prev = nullptr;
		node* cur = _table[hashi];
		while (cur)
		{
			//删除
			if (kot(cur->_data) == key)
			{
				if (prev == nullptr)
				{
					_table[hashi] = cur->_next;
				}
				else
				{
					prev->_next = cur->_next;
				}

				delete cur;

				return true;
			}

			prev = cur;
			cur = cur->_next;
		}

		return false;
	}

	void print()
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				node* cur = _table[i];
				while (cur)
				{
					std::cout << "[" << i << "]->" << cur->_kv.first <<
						":" << cur->_kv.second << " ";

					cur = cur->_next;
				}
				std::cout << std::endl;
			}
			else
			{
				printf("[%d]->\n", i);
			}
		}
	}

	~HashBucket()
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			node* del = _table[i];
			while (del)
			{
				node* next = del->_next;
				delete del;
				del = next;
			}

			_table[i] = nullptr;
		}
	}

	//桶情况
	void some()
	{
		/*size_t bucketsize = 0;
		size_t maxbucketlen = 0;
		size_t sum = 0;
		double averagebucketlen = 0;

		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				node* cur = _table[i];
				int len = 0;
				while (cur)
				{
					cur = cur->_next;
					len++;
				}

				if (maxbucketlen < len)
				{
					maxbucketlen = len;
				}
				sum += len;
				bucketsize++;
			}
		}

		averagebucketlen = (double)sum / (double)bucketsize;

		printf("哈希表大小:%d\n", _table.size());
		printf("桶大小:%d\n", bucketsize);
		printf("最大桶:%d\n", maxbucketlen);
		printf("平均桶:%lf\n", averagebucketlen);*/
		size_t bucketSize = 0;
		size_t maxBucketLen = 0;
		size_t sum = 0;
		double averageBucketLen = 0;

		for (size_t i = 0; i < _table.size(); i++)
		{
			node* cur = _table[i];
			if (cur)
			{
				++bucketSize;
			}

			size_t bucketLen = 0;
			while (cur)
			{
				++bucketLen;
				cur = cur->_next;
			}

			sum += bucketLen;

			if (bucketLen > maxBucketLen)
			{
				maxBucketLen = bucketLen;
			}
		}

		averageBucketLen = (double)sum / (double)bucketSize;

		printf("插入数据:%d\n", _n);
		printf("all bucketSize:%d\n", _table.size());
		printf("bucketSize:%d\n", bucketSize);
		printf("maxBucketLen:%d\n", maxBucketLen);
		printf("averageBucketLen:%lf\n\n", averageBucketLen);

	}

private:
	std::vector<node*> _table;
	size_t _n = 0;  //个数
};

unordset

K和V都传K,为了保证key不能修改,使用const迭代器,hash字符串转换模板在这一层传入
在这里插入图片描述在这里插入图片描述
插入的返回值是pair,这里哈希表返回的是普通迭代器,需要构造成const迭代器返回

std::pair<const_iterator, bool> insert(const K& key)
{
	auto ret = _ht.insert(key);
	return std::pair<const_iterator, bool>(const_iterator(ret.first._node,
		ret.first._pht, ret.first._hashi), ret.second);
}

#pragma once
#include "hashpackage.h"

template <class K, class Hash = HashFunc<K>>
class unordset
{
	struct SetOfK
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

	
public:
	typedef typename HashBucket<K, K, SetOfK, Hash>::const_iterator iterator;
	typedef typename HashBucket<K, K, SetOfK, Hash>::const_iterator const_iterator;
	const_iterator begin() const
	{
		return _ht.begin();
	}

	const_iterator end() const
	{
		return _ht.end();
	}

	std::pair<const_iterator, bool> insert(const K& key)
	{
		auto ret = _ht.insert(key);
		return std::pair<const_iterator, bool>(const_iterator(ret.first._node,
			ret.first._pht, ret.first._hashi), ret.second);
	}

	iterator find(const K& key)
	{
		return _ht.find(key);
	}

	bool erase(const K& key)
	{
		return _ht.erase(key);
	}

private:
	HashBucket<K, K, SetOfK, Hash> _ht;
};

unordsmap

提供[]运算,返回迭代器的数据
在这里插入图片描述

#pragma once
#include "hashpackage.h"

template <class K, class V, class Hash = HashFunc<K>>
class unordmap
{
	struct SetOfV
	{
		const K& operator()(const std::pair<K, V>& kv)
		{
			return kv.first;
		}
	};
public:
	
	typedef typename HashBucket<K, std::pair<const K, V>, SetOfV, Hash>::iterator iterator;
	iterator begin()
	{
		return _ht.begin();
	}

	iterator end()
	{
		return _ht.end();
	}

	std::pair<iterator, bool> insert(const std::pair<K, V>& kv)
	{
		return _ht.insert(kv);
	}

	V& operator[](const K& key)
	{
		std::pair<iterator, bool> ret = _ht.insert(std::make_pair(key, V()));
		return ret.first->second;
	}

	const V& operator[](const K& key) const
	{
		std::pair<iterator, bool> ret = _ht.insert(std::make_pair(key, V()));
		return ret.first->second;
	}

	iterator find(const K& key)
	{
		return _ht.find(key);
	}

	bool erase(const K& key)
	{
		return _ht.erase(key);
	}

private:
	HashBucket<K, std::pair<const K, V>, SetOfV, Hash> _ht;
};

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

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

相关文章

分布式数据库系统MyCat

MyCat简介 MyCat是一个开源的分布式数据库系统&#xff0c;是一个实现了MySQL协议的服务器&#xff0c;前端用户可以把它看作是一个数据库代理&#xff0c;用MySQL客户端工具和命令行访问&#xff0c;而其后端可以用MySQL原生协议与多个MySQL服务器通信&#xff0c;也可以用JD…

Tita的OKR:如何高效写好一个 OKR ?

OKR 是一个简单而强大的目标设定系统&#xff0c;世界各地的企业都依靠它来提高&#xff08;除其他外&#xff09;对战略、调整和参与的关注度。该系统由目标&#xff08;你想实现的目标&#xff09;和关键结果&#xff08;衡量目标实现情况的量化陈述&#xff09;组成。 目标…

参数页面设计

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 参数页面设计 {public partial class Form1 : Form{List<PMs> PMs new List<PMs>();public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){for (int …

element-ui table使用type=‘selection‘复选框全禁用-全选禁用_elementui table禁用全选

问题点&#xff1a;当条件数据全被禁用时&#xff0c;全选按钮不是禁用的状态。 复选框全被禁用时&#xff0c;全选按钮将被隐藏 问题总结&#xff1a; 当条件数据全被禁用时&#xff0c;全选按钮也变成禁用的状态&#xff0c;而不是隐藏。有会做的小伙伴希望跟帖。谢谢&#x…

PasteSpiderFile文件同步管理端使用说明(V24.6.21.1)

PasteSpider作为一款适合开发人员的部署管理工具&#xff0c;特意针对开发人员的日常情况做了一个PasteSpiderFile客户端&#xff0c;用于windows上的开发人员迅速的更新发布自己的最新代码到服务器上&#xff01; 虽然PasteSpider也支持svn/git的源码拉取&#xff0c;自动编译…

0802功放2

功放要记一般的式子&#xff0c;而非最大的式子&#xff0c;因为总不能总开到最大音量上工作&#xff0c;而是在比较合适的音量上工作 运放的最大电压也是比电源低1~2V 饱和三极管的功率&#xff0c;电流越大&#xff0c;饱和压降越大&#xff1f;&#xff1f;&#xff1f;不…

SpringBoot优点达项目实战:项目初始化(一)

SpringBoot优点达项目实战&#xff1a;项目初始化&#xff08;一&#xff09; 文章目录 SpringBoot优点达项目实战&#xff1a;项目初始化&#xff08;一&#xff09;1、项目介绍2、项目搭建3、依赖导入4、数据准备 1、项目介绍 技术框架 SpringbootmybatisPlusvueknife 2、项目…

机器学习之逻辑回归丨KNN测试

选择题 【 正确答案: A D】 A. B. C. D. 【 正确答案: B】 A. B. C. D. 【 正确答案: C, D】 A. B. C. D. 假设我们三个类别中心&#xff0c;若某测试样本为&#xff0c;它的 c ( i ) c^{(i)} c(i)是多少&#xff1f; 【 正确答案: B】 A.1 B.2 C.3 D.不确定 假设你…

跨境电商货源渠道哪里找?盘点11个拿货产业带

一、跨境货源渠道哪里找&#xff1f; 说到找货源&#xff0c;应该很多卖家都上过阿里巴巴1688“淘货”&#xff0c;阿里巴巴1688作为一个全球采购批发平台&#xff0c;在2017年上线了个跨境专供板块&#xff0c;专为跨境卖家供货&#xff0c;跨境专供板块的供货商需要经过严格…

将 MinIO 与 Keycloak OIDC 集成

Keycloak是一种单点登录解决方案。使用Keycloak&#xff0c;用户使用Keycloak而不是MinIO进行身份验证。如果没有Keycloak&#xff0c;您将不得不为每个用户创建一个单独的身份 - 从长远来看&#xff0c;这将很麻烦。您需要一个集中身份解决方案来管理 MinIO 的身份验证和授权。…

vue3 vxe-grid列中绑定vxe-switch实现数据更新

1、先上一张图&#xff1a; <template #valueSlot"{ row }"><vxe-switch :value"getV(row.svalue)" change"changeSwitch(row)" /></template>function getV(value){return value 1;};function changeSwitch(row) {console.l…

数据分析必备:一步步教你如何用matplotlib做数据可视化(11)

1、Matplotlib 三维绘图 尽管Matplotlib最初设计时只考虑了二维绘图&#xff0c;但是在后来的版本中&#xff0c;Matplotlib的二维显示器上构建了一些三维绘图实用程序&#xff0c;以提供一组三维数据可视化工具。通过导入Matplotlib包中包含的mplot3d工具包&#xff0c;可以启…

推荐免费好用的日历和浏览器,你一定要下载使用

猫眼浏览器 猫眼浏览器是一款基于Chromium内核的增强版网页浏览器&#xff0c;融合了Chrome的核心功能与Safari的优美外观。它以简约和安全为目标&#xff0c;提供了快速、流畅的网页加载和浏览体验。 猫眼浏览器内置了隐私保护和广告屏蔽功能&#xff0c;能够有效防止用户数据…

Linux tcpdump抓包必备知识

author: 放牛娃学编程 moto: 分享与热爱&#xff0c;不是大爱我不说 放牛娃每日一语: 除了你自己&#xff0c;没有人可以说你不行 别急着划开&#xff0c;这篇笔记一定能够给你带来收获 因为这里你能学到AI永远也给不了你的知识 Linux tcpdump抓包必备知识 文章目录 Linux tcp…

Vue3 头像是圆形,hover上去时头像出现黑色半透明样式,且中间显示修改两字的实现

实现效果 原头像 hover效果 实现方式 博主在实际开发过程中使用mouseover和mouseout会出现无法点击或hover频繁闪动的问题&#xff0c;故这里采用的是css中的hover&#xff0c;利用hover也能轻松实现上述效果&#xff0c;且完全不会影响点击事件的使用。 <template> &…

Mysql: 数据模型

一.关系型数据库 概念:建立在关系型基础上,由多张相互连接的二维表组成的数据库。 1.关系型数据库: 2.特点&#xff1a; 1.使用表存储数据,格式统一,便于维护。 2.使用SQL语言操作,标准统一,使用方便。 3.数据模型 通过客户端连接DBMS可以创建多个数据库,在数据库中…

TOPGP-TIPTOP调用外部Webservice

功能要求&#xff1a;ERP作业调用外部系统的webserice更新数据。 演示环境&#xff1a;ERP作业cooi002&#xff08;员工档案&#xff09;录入后更新到外部系统员工档案表。 1、外部系统的WebSerice使用.net搭建 2、在Service.cs中写一个调用方法erp_other erp_other中两个参数…

Windows 中 Chrome / Edge / Firefox 浏览器书签文件默认存储路径

1. Chrome 浏览器 按组合键 Win R&#xff0c;打开运行对话框&#xff0c;输入 %USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default或在Chrome 浏览器地址栏输入 chrome://version查看【个人资料路径】 2. Edge 浏览器 按组合键 Win R&#xff0c;打开运行对…

dockerfile文件的中的命令

# 基础镜像 FROM registry.cn-beijing.aliyuncs.com/205erp/myopenjdk:8.6 # 设置工作目录 WORKDIR /opt # 拷贝jar包到工作目录 COPY target/*.jar app.jar RUN ls # 设置暴漏的端口 EXPOSE 8080 # 启动jar包 CMD/ENTRYPOINT java ${JAVA_TOOL_OPTIONS} -jar app.jarCMD与ENT…

【uniapp】uniapp开发微信小程序入门教程

HBuilderx中uniapp开发微信小程序入门教程 一、 环境搭建 1. HBuilderx下载安装 HBuilderx下载安装地址 2. 微信开发者工具下载安装 微信开发者工地址具下载安装 二、创建uniapp项目 选择&#xff1a;文件>新建>项目>uni-app 输入项目名称>选择默认模板>…