【C++】unordered_map unordered_set 底层刨析

文章目录

  • 1. 哈希表的改造
  • 2. unordered_map
  • 3. unordered_set

在这里插入图片描述
C++ STL 库中,unordered_map 和 unordered_set 容器的底层为哈希表,本文将简单模拟哈希表(哈希桶),unordered_map 和 unordered_set 只需封装哈希表的接口即可实现。

1. 哈希表的改造

  1. 模板参数列表的改造

    • K:关键码类型
    • T:不同容器 T 的类型不同,如果是 unordered_map,T 代表一个键值对,如果是 unordered_set,T 为 K
    • KeyOfT:从 T 中获取 Key
    • Hash:哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将 Key 转换为整型数字才能取模
    template<class K, class T, class KeyOfT, class Hash>
    class HashTable;
    
  2. 增加迭代器操作

    // 为了实现简单,在哈希桶的迭代器类中需要用到HashTable本身
    template<class K, class T, class KeyOfT, class Hash>
    class HashTable;
    
    // 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作
    template<class K, class T, class KeyOfT, class Hash>
    struct __HTIterator
    {
    	typedef HashNode<T> Node;
    	typedef HashTable<K, T, KeyOfT, Hash> HT;
    	typedef __HTIterator<K, T, KeyOfT, Hash> Self;
    
    	Node* _node;	// 当前迭代器关联的节点
    	HT* _ht;		// 哈希桶 - 主要是为了找下一个空桶时候方便
    
    	__HTIterator(Node* node, HT* ht)
    		: _node(node)
    		, _ht(ht)
    	{}
    
    	T& operator*()
    	{
    		return _node->_data;
    	}
    
    	Self& operator++()
    	{
    		if (_node->_next)
    		{
    			// 当前桶还是节点
    			_node = _node->_next;
    		}
    		else
    		{
    			// 当前桶走完了,找下一个桶
    			KeyOfT kot;
    			Hash hs;
    			size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();
    			
    			// 找下一个桶
    			hashi++;
    			while (hashi < _ht->_tables.size())
    			{
    				if (_ht->_tables[hashi])
    				{
    					_node = _ht->_tables[hashi];
    					break;
    				}
    				hashi++;
    			}
    
    			// 后面没有桶了
    			if (hashi == _ht->_tables.size())
    			{
    				_node = nullptr;
    			}
    		}
    		return *this;
    	}
    
    	bool operator!=(const Self& s)
    	{
    		return _node != s._node;
    	}
    };
    
  3. 增加通过 T 获取 key 操作

    template<class K, class T, class KeyOfT, class Hash>
    class HashTable
    {
    	template<class K, class T, class KeyOfT, class Hash>
    	friend struct __HTIterator;
    
    	typedef HashNode<T> Node;
    
    public:
    	typedef __HTIterator<K, T, KeyOfT, Hash> iterator;
    
    	iterator begin()
    	{
    		for (size_t i = 0; i < _tables.size(); i++)
    		{
    			// 找到第一个桶的第一个节点
    			if (_tables[i])
    			{
    				return iterator(_tables[i], this);
    			}
    		}
    		return end();
    	}
    
    	iterator end()
    	{
    		return iterator(nullptr, this);
    	}
    
    	HashTable()
    	{
    		_tables.resize(10, nullptr);
    		_n = 0;
    	}
    
    	~HashTable()
    	{
    		for (size_t i = 0; i < _tables.size(); i++)
    		{
    			Node* cur = _tables[i];
    			while (cur)
    			{
    				Node* next = cur->_next;
    				delete cur;
    
    				cur = next;
    			}
    			_tables[i] = nullptr;
    		}
    	}
    
    	bool Insert(const T& data)
    	{
    		KeyOfT kot;
    
    		if (Find(kot(data)))
    			return false;
    
    		Hash hs;
    
    		// 负载因子到1就扩容
    		if (_n == _tables.size())
    		{
    			vector<Node*> newTables(_tables.size() * 2, nullptr);
    			for (size_t i = 0; i < _tables.size(); i++)
    			{
    				// 取出旧表中节点,重新计算挂到新表桶中
    				Node* cur = _tables[i];
    				while (cur)
    				{
    					Node* next = cur->_next;
    
    					// 头插到新表
    					size_t hashi = hs(kot(cur->_data)) % newTables.size();
    					cur->_next = newTables[hashi];
    					newTables[hashi] = cur;
    
    					cur = next;
    				}
    				_tables[i] = nullptr;
    			}
    			_tables.swap(newTables);
    		}
    
    		size_t hashi = hs(kot(data)) % _tables.size();
    		Node* newnode = new Node(data);
    
    		// 头插
    		newnode->_next = _tables[hashi];
    		_tables[hashi] = newnode;
    
    		++_n;
    		return true;
    	}
    
    	Node* Find(const K& key)
    	{
    		KeyOfT kot;
    		Hash hs;
    		size_t hashi = hs(key) % _tables.size();
    		Node* cur = _tables[hashi];
    		while (cur)
    		{
    			if (kot(cur->_data) == key)
    			{
    				return cur;
    			}
    			cur = cur->_next;
    		}
    		return nullptr;
    	}
    
    	bool Erase(const K& key)
    	{
    		KeyOfT kot;
    		Hash hs;
    		size_t hashi = hs(key) % _tables.size();
    		Node* prev = nullptr;
    		Node* cur = _tables[hashi];
    		while (cur)
    		{
    			if (kot(cur->_data) == key)
    			{
    				// 删除
    				if (prev)
    				{
    					prev->_next = cur->_next;
    				}
    				else
    				{
    					_tables[hashi] = cur->_next;
    				}
    
    				delete cur;
    
    				--_n;
    				return true;
    			}
    			prev = cur;
    			cur = cur->_next;
    		}
    		return false;
    	}
    
    private:
    	vector<Node*> _tables;	// 指针数组
    	size_t _n;
    };
    

2. unordered_map

  • unordered_map 中存储的是 pair<K, V> 的键值对,K 为 key 的类型,V 为 value 的类型,Hash 为哈希函数类型
  • unordered_map 在实现时,只需将 HashTable 中的接口重新封装即可
template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{
	// 通过T获取key的操作
	struct MapKeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};

public:
	typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;
		
	iterator begin()
	{
		return _ht.begin();
	}

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

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

private:
	hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
};

3. unordered_set

  • unordered_set 的实现类似于 unordered_map
template<class K, class Hash = HashFunc<K>>
class unordered_set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

public:
	typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;

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

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

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

private:
	hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
};

END

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

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

相关文章

专业SEO优化指南:设置网站关键词的详细步骤

在网站SEO优化的过程中&#xff0c;关键词的设置是提升网站排名的关键步骤之一。那么&#xff0c;作为一名专业的SEO人员&#xff0c;如何有效地进行关键词设置呢&#xff1f;以下是一些详细的步骤&#xff1a; 1. 确定网站的核心关键词。 这需要深入理解网站的主题或产品。通…

稀碎从零算法笔记Day49-LeetCode:设计哈希集合

题型&#xff1a;模拟 链接&#xff1a;705. 设计哈希集合 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 不使用任何内建的哈希表库设计一个哈希集合&#xff08;HashSet&#xff09;。 实现 MyHashSet 类&#xff1a; void add(key) 向哈…

封装原生html的table处理方法【参数类似eltable】

直接跑html即可 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>封装原生talbe</title> </…

“书写梦想 快乐成长”——沱江社区雏鹰活动(一)

为了丰富社区青少年精神文化生活&#xff0c;发挥社区服务青少年的功能和作用&#xff0c;2024年4月13日上午9点&#xff0c;中共新都区新都街道沱江社区委员会、沱江社区居民委员会联合成都市新都区领航社会工作服务中心举办的“书写梦想 快乐成长”——沱江社区雏鹰活动在沱江…

图灵奖简介及2023年获奖者Avi Wigderson的贡献

No.内容链接1Openlayers 【入门教程】 - 【源代码示例300】 2Leaflet 【入门教程】 - 【源代码图文示例 150】 3Cesium 【入门教程】 - 【源代码图文示例200】 4MapboxGL【入门教程】 - 【源代码图文示例150】 5前端就业宝典 【面试题详细答案 1000】 文章目录 2023年的…

✌粤嵌—2024/3/19—环形链表

代码实现&#xff1a; 快慢指针&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ bool hasCycle(struct ListNode *head) {// 快慢指针&#xff1a;快指针每次走两步&#xff0c;慢指针每次走一步&a…

近屿OJAC带你解读:什么是GAN生成式对抗网络?

生成式对抗网络(GAN&#xff0c;英文全称Generative Adversarial Network)是一种深度学习模型&#xff0c; 由于其生成高质量、真实数据的能力&#xff0c;近年来获得了极大的关注。GAN已被用于广泛的应用 中&#xff0c;包括图像合成、⻛格转移和数据增强。 GAN的核心思想是通…

《springcloud alibaba》 六 微服务链路跟踪skywalking

目录 准备调整配置接入多个微服务网关项目调整order-seata项目stock-seata项目测试 接入网关微服务 skywalking持续化到mysql自定义链路跟踪pom .xmlorderControllerOrderServiceOrderDaoOrderTblMapper.xml测试 性能剖析日志tid打印pom.xmllogback-spring.xml日志收集启动项目…

Unity类银河恶魔城学习记录12-7-2 p129 Craft UI - part 2源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_CraftWindow.cs using UnityEngine.UI; using TMPro; using UnityEngin…

OpenCV轻松入门(七)——HSV颜色模型图像特效案例:判断白天夜晚抠图颜色过滤替换背景图

HSV模型解释 HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。 这个模型中颜色的参数分别是&#xff1a; 色调&#xff08;H&#xff09;饱和度&#xff08;S&#xff09;明度&#xff08;V&…

为什么不用低代码平台制作网站,套用这11个商城主题模板,让程序员解放双手

随着人工智能技术的迅猛发展&#xff0c;众多复杂工作变得愈发简便。二十年前&#xff0c;构建一个在线商城并处理支付交易是一项艰巨任务&#xff0c;而正是在那个时代&#xff0c;零售巨头淘宝和京东崭露头角。如今&#xff0c;我们迎来了新时代&#xff0c;众多高效工具应运…

Dinov2 + Faiss 图片检索

MetaAI 通过开源 DINOv2&#xff0c;在计算机视觉领域取得了一个显着的里程碑&#xff0c;这是一个在包含1.42 亿张图像的令人印象深刻的数据集上训练的模型。产生适用于图像级视觉任务&#xff08;图像分类、实例检索、视频理解&#xff09;以及像素级视觉任务&#xff08;深度…

看完不会来揍我 | 孟德尔随机化(二)—— 代码实操 | 附代码注释 + 结果解读

最近真的是超超超超超超超级多的小伙伴们在咨询孟德尔随机化相关的问题和课程&#xff0c;意想不到的那种多&#xff01;那我怎么办嘞&#xff01;整呗&#xff01;主打的就是一个宠粉&#xff01; 关于孟德尔随机化&#xff0c;我们之前就已经在孟德尔随机化&#xff08;一&am…

PHP学习(二)

一、php 数据类型之查看和判断数据类型 查看数据类型 1.gettype(传入一个变量) 能够获得变量的类型 2.var_dump(传入一个变量) 输出变量类型和值 <?php //声明一个变量 88.8 $f 88.8; $type gettype($f); echo $type; ?> <?php //多换几个类型试试 $str 你…

【wu-framework-parent】官网介绍

官网地址 介绍 springboot 版本3.2.1 wu-framework-parent 是一款由Java语言开发的框架&#xff0c;目标不写代码但是却能完成功能。 框架涵盖无赖ORM( wu-framework-lazy-orm-spring-starter)、仿生组件 、easy框架系列【Easy-Excel、easy-listener、easy-upsert】 授权框架…

数字乡村创新实践探索农业现代化与农村治理现代化新路径:科技赋能农村全面振兴与农民幸福生活

目录 引言 一、数字乡村与农业现代化 1、智慧农业技术的应用 2、农业产业链的数字化转型 二、数字乡村与农村治理现代化 1、农村信息化水平的提升 2、农村治理模式的创新 三、科技赋能农村全面振兴与农民幸福生活 1、提升农业生产效益与农民收入 2、促进农村产业结构…

[每周一更]-第93期:探索大型生成式聊天工具:从ChatGPT到未来

随着人工智能技术的不断进步&#xff0c;生成式聊天工具正逐渐成为人们日常生活中的一部分。这些工具利用深度学习技术和大规模语言模型的强大能力&#xff0c;能够与用户进行自然、流畅的对话&#xff0c;为我们提供了更加智能和个性化的交流体验。 ChatGPT&#xff1a;开启生…

mac电脑软件 Magnet v2.14.0免激活中文版

Magnet是一款窗口管理工具&#xff0c;适用于Mac操作系统。它可以帮助用户轻松地管理和组织多个应用程序的窗口&#xff0c;提高工作效率。 Magnet支持多种窗口布局和组合方式&#xff0c;可以将窗口分为左右、上下、四分之一等不同的比例和位置&#xff0c;用户可以根据实际需…

Linux:Redis7.2.4的简单在线部署(1)

注意&#xff1a;我写的这个文章是以最快速的办法去搭建一个redis的基础环境&#xff0c;作用是为了做实验简单的练习&#xff0c;如果你想搭建一个相对稳定的redis去使用&#xff0c;可以看我下面这个文章 Linux&#xff1a;Redis7.2.4的源码包部署&#xff08;2&#xff09;-…

测试人必看,小程序常见问题

小程序是一种轻盈的存在&#xff0c;用户无需为了使用它而下载和安装。它依附于微信这个强大的平台&#xff0c;只需轻轻一扫或一搜&#xff0c;它便跃然屏上&#xff0c;随时服务。小程序为我们带来更多前所未有的惊喜和便利&#xff0c;以下分享关于小程序相关的热门问题。 …