C++进阶:哈希表封装unordered_map和unordered_set(模拟实现)

基于开散列封装哈希表:

HashTable.h

#pragma once
#include<vector>template<class K>
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};// 特化
template<>
struct HashFunc<string>
{// abcd// bcad// aadd// BKDRsize_t operator()(const string& key){size_t hash = 0;for (auto ch : key){hash *= 131;hash += ch;}return hash;}
};namespace hash_bucket
{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}};// 前置声明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 __HTIterator<K, T, KeyOfT, Hash> Self;//	Node* _node;//	HashTable<K, T, KeyOfT, Hash>* _pht;//	__HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)//		:_node(node)//		,_pht(pht)//	{}//	T& operator*()//	{//		return _node->_data;//	}//	Self& operator++()//	{//		if (_node->_next)//		{//			// 当前桶没走完,找当前桶的下一个节点//			_node = _node->_next;//		}//		else//		{//			// 当前桶走完了,找下一个不为空的桶的第一个节点//			KeyOfT kot;//			Hash hs;//			size_t i = hs(kot(_node->_data)) % _pht->_tables.size();//			++i;//			for (; i < _pht->_tables.size(); i++)//			{//				if (_pht->_tables[i])//					break;//			}//			if (i == _pht->_tables.size())//			{//				// 所有桶都走完了,最后一个的下一个用nullptr标记//				_node = nullptr;//			}//			else//			{//				_node = _pht->_tables[i];//			}//		}//		return *this;//	}//	bool operator!=(const Self& s)//	{//		return _node != s._node;//	}//};template<class K, class T, class KeyOfT, class Hash>class HashTable{typedef HashNode<T> Node;public:// 友元声明/*template<class K, class T, class KeyOfT, class Hash>friend struct __HTIterator;*/// 内部类template<class Ptr, class Ref>struct __HTIterator{typedef HashNode<T> Node;typedef __HTIterator Self;Node* _node;const HashTable* _pht;__HTIterator(Node* node, const HashTable* pht):_node(node), _pht(pht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}Self& operator++(){if (_node->_next){// 当前桶没走完,找当前桶的下一个节点_node = _node->_next;}else{// 当前桶走完了,找下一个不为空的桶的第一个节点KeyOfT kot;Hash hs;size_t i = hs(kot(_node->_data)) % _pht->_tables.size();++i;for (; i < _pht->_tables.size(); i++){if (_pht->_tables[i])break;}if (i == _pht->_tables.size()){// 所有桶都走完了,最后一个的下一个用nullptr标记_node = nullptr;}else{_node = _pht->_tables[i];}}return *this;}bool operator!=(const Self& s){return _node != s._node;}};typedef __HTIterator<T*, T&> iterator;typedef __HTIterator<const T*, const T&> const_iterator;iterator begin(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){// this -> HashTable*return iterator(cur, this);}}return end();}iterator end(){return iterator(nullptr, this);}const_iterator begin() const{for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){// this -> const HashTable*return const_iterator(cur, this);}}return end();}const_iterator end() const{return const_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;}}pair<iterator, bool> Insert(const T& data){KeyOfT kot;iterator it = Find(kot(data));if (it != end())return make_pair(it, false);Hash hs;// 扩容// 负载因子为1时扩容if (_n == _tables.size()){//HashTable<K, V> newHT;//newHT._tables.resize(_tables.size() * 2);旧表重新计算负载到新表//for (size_t i = 0; i < _tables.size(); i++)//{//	Node* cur = _tables[i];//	while (cur)//	{//		newHT.Insert(cur->_kv);//		cur = cur->_next;//	}//}//_tables.swap(newHT._tables);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 make_pair(iterator(newnode, this), true);}iterator 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 iterator(cur, this);}cur = cur->_next;}return end();}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 == nullptr){_tables[hashi] = 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 _n;//vector<list<pair<K, V>>> _tables;};//void TestHT1()//{//	int a[] = { 10001,11,55,24,19,12,31,4,34,44};//	HashTable<int, int> ht;//	for (auto e : a)//	{//		ht.Insert(make_pair(e, e));//	}//	ht.Insert(make_pair(32, 32));//	ht.Insert(make_pair(32, 32));//	ht.Erase(31);//	ht.Erase(11);//}//void TestHT2()//{//	HashTable<string, int> ht;//	ht.Insert(make_pair("sort", 1));//	ht.Insert(make_pair("left", 1));//	ht.Insert(make_pair("insert", 1));//}
}

基于哈希表实现unordered_set类

基于HashTable.h封装的哈希表类提供的接口,实现一个unordered_set类。

my_unordered_set.h

该文件基本实现了unordered_set类。

#pragma once#include"HashTable.h"namespace xx
{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;typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::const_iterator const_iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}const_iterator end() const{return _ht.end();}pair<iterator, bool> insert(const K& key){return _ht.Insert(key);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;};void Func(const unordered_set<int>& s){unordered_set<int>::iterator it = s.begin();while (it != s.end()){//*it = 1;cout << *it << " ";++it;}cout << endl;}void test_unordered_set(){unordered_set<int> s;s.insert(31);s.insert(11);s.insert(5);s.insert(15);s.insert(25);unordered_set<int>::iterator it = s.begin();while (it != s.end()){//*it = 1;cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;}
}

基于哈希表实现unordered_map类

基于my_unordered_map.h封装的哈希表类提供的接口,实现一个unordered_map。unordered_map的值是一个键值对。

Myunordered_map.h

该文件基本实现了unordered_map类。

#pragma oncenamespace xx
{template<class K, class V, class Hash = HashFunc<K>>class unordered_map{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();}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}pair<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;};void test_unordered_map(){string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };unordered_map<string, int> countMap;for (auto& e : arr){countMap[e]++;}unordered_map<string, int>::iterator it = countMap.begin();while (it != countMap.end()){//it->first += 'x'; // key不能修改it->second += 1;  // value可以修改cout << it->first << ":" << it->second << endl;++it;}cout << endl;for (auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}cout << endl;}
}

源文件test.cpp:
 

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;#include"HashTable.h"
#include"my_unordered_set.h"
#include"my_unordered_map.h"int main()
{xx::test_unordered_map();return 0;
}

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

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

相关文章

kvm学习 - 迅速上手示例

目录 kvmtool kvmsample kvmtool GitHub - kvmtool/kvmtool: Stand-alone Native Linux KVM Tool repoStand-alone Native Linux KVM Tool repo. Contribute to kvmtool/kvmtool development by creating an account on GitHub.https://github.com/kvmtool/kvmtool.git cd …

Wpf 使用 Prism 开发MyToDo应用程序

MyToDo 是使用 WPF &#xff0c;并且塔配Prism 框架进行开发的项目。项目中进行了前后端分离设计&#xff0c;客户端所有的数据均通过API接口获取。适合新手入门学习WPF以及Prism 框架使用。 首页统计以及点击导航到相关模块功能待办事项增删改查功能备忘录增删改查功能登录注册…

Vue渲染函数与JSX指南

title: Vue渲染函数与JSX指南 date: 2024/6/3 下午6:43:53 updated: 2024/6/3 下午6:43:53 categories: 前端开发 tags:Vue渲染JSX基础性能优化组件对比React JSX大项目测试策略 第1章&#xff1a;Vue.js入门 Vue.js的历史和背景 Vue.js是一个用于构建用户界面的JavaScript框…

Java流与链表:探索java.util.stream与LinkedList的交汇点

在现代Java开发中&#xff0c;流&#xff08;Streams&#xff09;和链表&#xff08;LinkedList&#xff09;都是强大且常用的数据处理工具。java.util.stream提供了高效的方式来处理数据流&#xff0c;而LinkedList则是java.util包中的经典集合实现。本文将探索它们的交汇点&a…

【Java】接口详解

接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含静态常量。 一个简单的接口代码示例 interface IShape { void draw(); } class Cycle implements IShape { Override public void draw() { System.out.println…

AdamW算法

AdamW算法是优化算法Adam的一个变体&#xff0c;它在深度学习中广泛应用。AdamW的主要改进在于它正则化方法的改变&#xff0c;即通过权重衰减&#xff08;weight decay&#xff09;而不是L2正则化&#xff0c;来控制模型参数的大小&#xff0c;从而提升了训练的稳定性和效果。…

鸿蒙ArkTS如何加载rawfile目录下的资源文件

1.鸿蒙resources/rawfile资源文件加载 如果rawfile目录的图片资源文件,可以通过资源ID的方式加载&#xff1b; Image($rawfile(login/account.png)).width(30).height(30) 那如果是txt&#xff0c;json&#xff0c;音频等文件呢&#xff1f; 可以通过ResourceManager进行加载…

【论文笔记】Content-based Unrestricted Adversarial Attack

图2&#xff1a;Adversarial Content Attack的流程。首先使用Image Latent Mapping将图像映射到潜变量空间。然后&#xff0c;用Adversarial Latent Optimization生成对抗性样本。最后&#xff0c;生成的对抗性样本可以欺骗到目标分类模型。 3.1 Image Latent Mapping 对于扩…

升级 macOS 12 之后,CleanMyMac 闪退怎么办?

​​好多朋友在升级 macOS 12 之后&#xff0c;发现 CleanMyMac 出现闪退问题&#xff0c;这可能是TNT的证书过期造成的&#xff0c;那么如何解决CleanMyMac闪退的问题呢&#xff1f; 今天给大家带来了三种解决方法&#xff0c;如下&#xff1a; 一、打开“终端”&#xff0c;运…

回溯算法常见思路

回溯问题 回溯法&#xff0c;一般可以解决如下几种问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题&#xff1a;一个字符串按一定规则有几种切割方式子集问题&#xff1a;一个N个数的集合里有多少符合条件的子集排列问题&#xff1a;N个数…

Java数据结构与算法(有向无环图)

前言 有向无环图&#xff08;Directed Graph&#xff09;是在有向图的基础上&#xff0c;增加无环的检查。 实现原理 使用邻接表表示法实现有向图相对简单明了&#xff0c;步骤也相对简单。 1:首先创建有向图 2.创建顶点 3.顶点间创建边 4.创建边的过程中检查节点是否存…

for深入学习

目录 练习&#xff1a; 例1&#xff1a; 求解0-100中整除3的数有哪些 例2&#xff1a; 求0-100中含数字9个个数 作业&#xff1a; 练习&#xff1a; 例1&#xff1a; 求解0-100中整除3的数有哪些 代码&#xff1a; #include<stdio.h> int main() {printf("整…

揭秘!天工AI如何帮我轻松搞定产品经理工作,低调强大

聊到AI搜索&#xff0c;总会想起那句话&#xff1a;“领导者和追随者最大的区别在于创新” 作为一名AI产品经理&#xff0c;我深刻体会到搜索引擎对我们日常生活的重要性&#xff0c;在本文中我将会分享我是如何使用图文并茂的天工AI搜索引擎辅助我完成产品经理的工作。 从最初…

Anaconda中的常用科学计算工具

Anaconda中的常用科学计算工具 Anaconda是一个流行的Python科学计算环境&#xff0c;它提供了大量的科学计算工具&#xff0c;这些工具可以帮助用户进行数据分析、机器学习、深度学习等任务。以下是一些常见的Anaconda中的科学计算工具&#xff1a; NumPy&#xff1a;一个用于…

强大的机器学习建模扩展包:mlxtend

公众号&#xff1a;尤而小屋编辑&#xff1a;Peter作者&#xff1a;Peter 大家好&#xff0c;我是Peter~ 今天给大家介绍一个强大的机器学习建模扩展包&#xff1a;mlxtend。 mlxtend(machine learning extensions&#xff0c;机器学习扩展)是一个用于日常数据分析、机器学习…

LeetCode216组合总和3

题目描述 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a;只使用数字1到9。每个数字 最多使用一次。返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 解析 递归加剪枝&#xff0c;搜索长度达…

基于JSP的美食推荐管理系统

你好呀&#xff0c;我是学长猫哥&#xff01;如果有需求可以文末加我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSPJavaBeansServlet 系统展示 首页 用户注册 用户登录 热门美食 摘要 本文介绍了一个基于JSP技术的美食推荐管理系统&#xff0…

PDFBox读取pdf的每一行内容

在Java中读取PDF文件并获取其“格式”通常指的是提取PDF文档中的不同内容类型&#xff0c;如文本、图像、字体、元数据等。但是&#xff0c;要注意的是&#xff0c;PDF并没有一个统一的“格式”定义&#xff0c;因为它是一个复杂的文档格式&#xff0c;可以包含各种元素和属性。…

企业内业务系统与Activiti流程引擎的结合(十一)

摘要:前文分享了企业内部系统集成Activiti的架构和API设计,这里再介绍下 bpmn 流程图的绘制以及与 流程图与bpm后台服务代码的结合点。 一、画流程图 以使用 eclipse 画流程图为例 1. 将 Activiti BPMN 插件安装到 eclipse 插件安装成本后的效果:新建向导中出现 Activiti…

ARM公司发展历程

Arm从1990年成立前开始&#xff0c;历经漫长岁月树立各项公司里程碑及产品成就&#xff0c;一步步成为全球最普及的运算平台。 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; Acorn 时期 1978年&#xff0c;Chris Curry和Hermann Hauser共同创立了Acorn…