unordered_mapunordered_set封装

map&&set

  • unordered_map&&unordered_set介绍
  • unordered_set
  • 哈希桶的封装部分
  • unordered_map的封装
  • unordered_set封装

unordered_map&&unordered_set介绍

看名字是和map\set类似的迭代器,和map\set的区别如下:

  1. map底层是红黑树封装;unordered_map底层是哈希桶
  2. map支持双向迭代器;unordered_map只支持++
  3. map是有序的序列;unordered_map是无序的序列
  4. unordered_map的查找效率比map快

接口方面和map类似,参照map/set的使用即可。

unordered_set

哈希桶的封装部分

哈希桶的代码:哈希桶代码部分参考这里
为了更好适合封装map,在哈希桶里面修改内容如下:

  1. 添加了迭代器,提供了*,->,++,!=等功能。
  2. 哈希桶增加了begin和end函数
  3. 哈希桶insert的返回值修改(为了在map里实现[])
  4. 添加了const迭代器

具体实现出现的问题,在代码的注释中,有所体现:

namespace HashBucket
{//T表示数据类型template<class T>struct Elem{Elem(const T& data):_data(data), _next(nullptr){}T _data;Elem<T>* _next;};template<class K>struct Hash{size_t operator()(const K& key){return key;}};//特化版本template<>struct Hash<string>{//BKDR哈希*31size_t operator()(const string& s){size_t hash = 0;for (auto e : s){hash += e;hash *= 31;}return hash;}};//迭代器实现//迭代器用到了哈希表,需要前置声明一下(声明不需要写默认传参)template<class K, class T, class KeyOFT, class HashFunc>class HashTables;// K索引, T数据类型, Ref:T的引用 , Ptr:T的指针, KeyOFT:获取T的索引template<class K, class T, class Ref, class Ptr, class KeyOFT, class HashFunc = Hash<K>>struct _HashIterator{typedef Elem<T> Node;typedef HashTables<K, T, KeyOFT, HashFunc> HT;typedef _HashIterator<K, T, Ref, Ptr, KeyOFT, HashFunc> Self;typedef _HashIterator<K, T, T&, T*, KeyOFT, HashFunc> Iterator;//const迭代器,不在这定义,在哈希表定义//typedef _HashIterator<K, const T, const T&, const T*, KeyOFT, HashFunc> const_Iterator;/*typedef _HashIterator<K, T, const T&, const T*, KeyOFT, HashFunc> const_Iterator;*/Node* _node;const HT* _ht;   //迭代器还需要哈希表,因为要换桶,没有表无法完成换桶//构造  begin要用,所以要publicpublic:_HashIterator(Node* node, const HT* ht):_node(node),_ht(ht){}//如果是普通迭代器,就是拷贝构造//如果是const,就是构造函数//_HashIterator(const Iterator& it)//	:_node(it._node)//	, _ht(it._ht)//{}public:Ptr operator->(){return &(_node->_data);}//没有形参//Ref operator->(const Node* node)Ref operator*(){return _node->_data;}// !=号的迭代器注意一下bool operator!=(const Self& s){return _node != s._node;}Self& operator++(){//next不为空,下一个结点就是nextif (_node->_next){_node = _node->_next;return *this;}KeyOFT kot;HashFunc hash;//首先确认桶号size_t hashi = hash(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;}};//K表示查找值时的索引, T表示数据类型,KeyOFT获取T的索引K,HashFunc计算Hash的函数template<class K, class T, class KeyOFT, class HashFunc = Hash<K>>class HashTables{//迭代器要访问私有的_tables,得是友元template<class K, class T, class Ref, class Ptr, class KeyOFT, class HashFunc>friend struct _HashIterator;typedef Elem<T> Node;    typedef T Data;//迭代器的typedef,//unordered_map的public:typedef _HashIterator<K, T, T&, T*, KeyOFT, HashFunc> iterator;//const 迭代器typedef _HashIterator<K, T, const T&, const T*, KeyOFT, HashFunc> const_iterator;public://此版本不太好//Iterator begin()//{//	Node* cur = nullptr;//	for (auto e : _tables)//	{//		if (e)//		{//			return Iterator(e, this);//		}//	}//}iterator begin(){Node* cur = nullptr;for (auto e : _tables){if (e){cur = e;break;}}return iterator(cur, this);}iterator end(){return iterator(nullptr, this);}const_iterator begin() const{Node* cur = nullptr;for (auto e : _tables){if (e){cur = e;break;}}return const_iterator(cur, this);}const_iterator end() const{return const_iterator(nullptr, this);}pair<iterator, bool> insert(const Data& data){//负载因子过大就扩容CheckCapacity();HashFunc hash;KeyOFT kot;iterator it = find(kot(data));//if (it._node)    //查到了,直接返回,不能访问迭代器的成员变量if(it!=end()){/*return make_pair(iterator(cur,this), false);*/return make_pair(it, false);}//散列地址size_t hashi = hash(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){HashFunc hash;KeyOFT kot;size_t hashi = hash(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){HashFunc hash;KeyOFT kot;size_t hashi = hash(key) % _tables.size();Node* cur = _tables[hashi];Node* prev = nullptr;while (cur){if (kot(cur->_data) == key){if (!prev)   //prev为空,说明是在表上{_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;return true;}prev = cur;cur = cur->_next;}return false;}private://扩容有问题,不应该插入一个就扩容,插入一个就扩容!!!!!!!!!!!!void CheckCapacity(){KeyOFT kot;HashFunc hash;//表为空或者负载因子大于0.7了就扩容//if (!_tables.size() || ((n * 10) / (_tables.size() * 10) > 7))/*if (!_tables.size() || ((n * 10) / _tables.size() > 7))*/if (n == _tables.size()){size_t newCapacity = (_tables.size() == 0 ? 10 : _tables.size() * 2);HashTables* newHashTable = new HashTables;newHashTable->_tables.resize(newCapacity);//将旧表的数据重新映射到新表//遍历旧表for (auto& e : _tables){if (e)  //不空,就有数据{Node* cur = e;Node* next;   //下一个指针while (cur){size_t hashi = hash(kot(cur->_data)) % newCapacity;next = cur->_next;  //暂存下一个cur->_next = newHashTable->_tables[hashi];newHashTable->_tables[hashi] = cur;     //头插//newHashTable->n++;cur = next;}}}//swap(*newHashTable, *this);_tables.swap(newHashTable->_tables);}}private:vector<Node*> _tables;size_t n = 0;};
}

unordered_map的封装

  1. 迭代器类中只实现基本的操作不实现begin/end,哈希桶表提供begin/end,哈希桶里面通过typedef实现const迭代器的规则;
  2. map外面暴露了三个模板参数,可以自定义hash函数
  3. 支持[]取数据
  4. 注意成员变量定义方法
namespace xty
{template<class K>struct Hash{size_t operator()(const K& key){return key;}};//特化版本template<>struct Hash<string>{//BKDR哈希*31size_t operator()(const string& s){size_t hash = 0;for (auto e : s){hash += e;hash *= 31;}return hash;}};template<class K, class V,class HashFunc=Hash<K>>class unordered_map{struct MyKeyOFT;   //声明一下//迭代器重命名public:typedef typename HashBucket::HashTables<K, pair<const K, V>, MyKeyOFT, HashFunc>::iterator iterator;typedef typename HashBucket::HashTables<K, pair<const K, V>, MyKeyOFT, HashFunc>::const_iterator const_iterator;private://只有自己知道自己的数据类型是什么样struct MyKeyOFT{const K& operator()(const pair<K, V>& data){return data.first;}};public:iterator begin(){return _hash.begin();}iterator end(){return _hash.end();}//要让map支持[],需要将insert的返回函数修改一下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>& data){return _hash.insert(data);}//删除bool Erase(const K& key){return _hash.erase(key);}pair<K, V>* Find(const K& key){return _hash.find(key);}private:HashBucket::HashTables<K, pair<const K, V>, MyKeyOFT, HashFunc> _hash;//HashBucket::HashTables<K, V, MyKeyOFT> _hash;   注意要传pair ,不然insert报错};void unordered_map_test(){int a[]= { 11, 22, 33, 44, 55, 66, 77, 88, 99, 111, 444, 555,1111 };unordered_map<int, int> map;for (auto e : a){map.Insert(make_pair(e, e));}}
}

添加一段测试代码检验第三个模板参数的正确性:

class Date{friend struct HashDate;public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}bool operator==(const Date& d) const{return _year == d._year&& _month == d._month&& _day == d._day;}friend ostream& operator<<(ostream& _cout, const Date& d);private:int _year;int _month;int _day;};ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}struct HashDate{size_t operator()(const Date& d){size_t hash = 0;hash += d._year;hash *= 31;hash += d._month;hash *= 31;hash += d._day;hash *= 31;return hash;}};// 一个类型要做unordered_map/unordered_set的key,要满足支持转换成取模的整形 和 ==比较// 一个类型要做map/set的key,要满足支持<比较/*if (cur->key < key){}else if (key < cur->key){}else{}*/void test_unordered_map4(){Date d1(2023, 3, 13);Date d2(2023, 3, 13);Date d3(2023, 3, 12);Date d4(2023, 3, 11);Date d5(2023, 3, 12);Date d6(2023, 3, 13);Date a[] = { d1, d2, d3, d4, d5, d6 };unordered_map<Date, int, HashDate> countMap;for (auto e : a){countMap[e]++;}for (auto& kv : countMap){cout << kv.first << ":" << kv.second << endl;}}

unordered_set封装

  1. 注意成员变量的参数不加const K
  2. typename
	template<class K, class HashFunc=Hash<K>>class unordered_set{struct SetOFT;public://外面要使用迭代器,所以放publictypedef typename HashBucket::HashTables<K, K, SetOFT, HashFunc>::const_iterator iterator;typedef typename HashBucket::HashTables<K, K, SetOFT, HashFunc>::const_iterator const_iterator;public:struct SetOFT{const K& operator()(const K& key){return key;}};iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}const_iterator begin() const{return _ht.begin();}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://不加pair<K,K>/*HashBucket::HashTables<K, pair<K, K>, SetOFT, HashFunc>*//*HashBucket::HashTables<K, const K, SetOFT, HashFunc> _ht;*/HashBucket::HashTables<K, K, SetOFT, HashFunc> _ht;};

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

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

相关文章

C++ STL中list迭代器的实现

list 的模拟实现中&#xff0c;重难点在于迭代器功能的实现&#xff0c;因此本文只围绕 iterator 及 const_iterator 的设计进行介绍&#xff0c;其余如增删查改则不再赘述——在C语言的基础上&#xff0c;这些都非常简单。 与 string / vector 不同&#xff0c;list 的节点原生…

C++11 unordered_map使用哈希实现,map是使用红黑树实现的

unordered_map C++11 引入了一套标准库中的哈希函数和哈希容器,用于提供高效的哈希功能。这些特性位于 <unordered_map> 和 <unordered_set> 头文件中。 C++11 中的哈希容器是基于散列表实现的,可以快速插入、查找和删除元素,并具有平均常数时间复杂度的操作。…

【时间安排】

最近刚刚回到家&#xff0c;到家就是会有各种事情干扰&#xff0c;心里变乱人变懒的&#xff0c;而要做的事情也要继续&#xff0c;写论文&#xff0c;改简历&#xff0c;学习新技能。。 明天后天两天写论文改简历 周一&#xff08;早上去城市书房&#xff0c;可能吵一点戴个耳…

C#学习笔记_变量、数据类型、数据类型转换

变量 一、概念 变量是用于在计算机的内存中存储数据。 二、语法 声明变量&#xff1a;数据类型 变量名; 变量赋值&#xff1a;变量名 表达式;使用变量&#xff1a;变量名 具体可见以下代码&#xff1a; using System; using System.Collections.Generic; using System.L…

【深度学习:开源BERT】 用于自然语言处理的最先进的预训练

【深度学习&#xff1a;开源BERT】 用于自然语言处理的最先进的预训练 是什么让 BERT 与众不同&#xff1f;双向性的优势使用云 TPU 进行训练BERT 结果让 BERT 为您所用 自然语言处理 &#xff08;NLP&#xff09; 面临的最大挑战之一是训练数据的短缺。由于 NLP 是一个具有许多…

C#学习(十一)——Array和Collection

一、集合 集合重要且常用 孤立的数据是没有意义的&#xff0c;集合可以作为大量数据的处理&#xff0c;可进行数据的搜索、迭代、添加、删除。 C#中&#xff0c;所有集合都必须实现ICollection接口&#xff08;数组Array除外&#xff09; 集合说明Array数组&#xff0c;固定长…

【GitHub项目推荐--基于 AI 的口语训练平台】【转载】

Polyglot Polyglot 是一个开源的基于 AI 的口语训练平台客户端&#xff0c;可以在 Windows、Mac 上使用。 比如你想练习英语口语&#xff0c;只需在该平台配置一个虚拟的 AI 国外好友&#xff0c;你可以通过发语音的方式和 AI 好友交流&#xff0c;通过聊天的方式提升你的口…

中仕教育:事业单位考试考什么?

事业单位考试分为两个阶段&#xff0c;分别是笔试和面试&#xff0c;考试科目包括公共科目和专业科目两部分。 公共科目内容是公共基础知识、职业能力测试或申论。一种形式为&#xff1a;公共基础知识职业能力测试或职业能力测试申论。另一种形式为&#xff1a;公共基础申论。…

c语言基础6

1.逗号表达式 逗号表达式&#xff0c;就是用逗号隔开的多个表达式。 逗号表达式&#xff0c;从左向右依次执行。整个表达式的结果是最后⼀个表达式的结果。 我们来看下面的一个代码&#xff1a; int main() {int a 1;int b 2;int ret (a > b, a b 2, b, b a 1);p…

Nginx实现反向代理负载均衡实验

实验环境&#xff1a; VM REdhat虚拟机&#xff08;192.168.87.5&#xff09;一台、VM Redhat虚拟机&#xff08;192.168.87.3&#xff09;一台、阿里云服务器&#xff08;47.93.79.92&#xff09;一台 实验要求&#xff1a;通过windows浏览器访问192.168.87.5&#xff08;虚…

通信协议的TCP/IP模型

昨天因为有事情&#xff0c;就没更新因特网模型协议栈( The Internet protocol stack)&#xff0c; 也有地方叫 TCP/IP协议套件(TCP/IP protocol suite)&#xff0c;该协议栈目前能找到的最早记录在由五层组成&#xff1a;物理层(Physical Layer)、 链路层(Link Layer)、网络层…

《合成孔径雷达成像算法与实现》Figure5.19

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

仰暮计划|“她就是用她的一双小脚把我们兄弟姐妹几个拉扯大的”

在残存的一些老物件中&#xff0c;在一些泛黄的相片中&#xff0c;掩藏着岁月的冲刷和青葱的时光。曾经无忧无虑的少女早已白发苍苍&#xff0c;不复青春貌美&#xff1b;曾经在父母面前笑闹的孩子早已变成他人眼中的长辈。 ——题记 她的身影也许并不高大&#xff0c;甚至还略…

Linux编辑器vim(含vim的配置)

文章目录 前言vim的基本概念vim基本操作进入vim模式切换退出vim vim指令vim命令模式指令vim底行模式命令 简单vim配置 前言 本篇文章&#xff0c;小编将介绍Linux编辑器–>vim以及vim的配置。 vim的基本概念 正常/普通/命令模式(Normal mode) 控制屏幕光标的移动&#xf…

Gin 框架之jwt 介绍与基本使用

文章目录 一.JWT 介绍二.JWT认证与session认证的区别2.1 基于session认证流程图2.2 基于jwt认证流程图 三. JWT 的构成3.1 header : 头部3.2 payload : 负载3.2.1 标准中注册的声明 (建议但不强制使用)3.2.2 公共的声明3.2.3 私有的声明3.2.4 定义一个payload 3.3 signatrue : …

【计算机网络】概述|分层体系结构|OSI参考模型|TCP/IP参考模型|网络协议、层次、接口

目录 一、思维导图 二、计算机网络概述 1.计算机网络定义、组成、功能 2.计算机网络分类 3.计算机网络发展历史 &#xff08;1&#xff09;计算机网络发展历史1&#xff1a;ARPANET->互联网 &#xff08;2&#xff09;计算机网络发展历史2&#xff1a;三级结构因特网 …

jenkins对接K8S

创建连接K8S的凭据 查看需要使用到的命名空间 [rootk8s ~]# kubectl get ns |grep arts-system arts-system Active 16d创建service accounts [rootk8s ~]# kubectl create sa jenkins-k8s -n arts-system serviceaccount/jenkins-k8s created [rootk8s ~]# kubectl…

一键批量处理,轻松为HTML文本添加所需内容

你是否曾经遇到过需要批量处理大量HTML文本的情况&#xff1f;是否曾经因为一个个编辑而感到繁琐和无趣&#xff1f;现在&#xff0c;这些问题都可以得到轻松解决&#xff01;我们的文本批量处理工具&#xff0c;为你提供一站式的服务&#xff0c;让你告别重复繁琐的操作&#…

java eazyexcel 实现excel的动态多级联动下拉列表(2)使用MATCH+OFFSET函数

原理 同样是将数据源放到一个新建的隐藏的sheet中&#xff0c;第一行是第一个列表的数据&#xff0c;第二行是每一个有下级菜单的菜单&#xff0c;他下面的行就是他下级菜单的每一值使用MATCH函数从第二行找到上级菜单对应的列根据OFFSET函数从2中获取的列&#xff0c;取得下级…

深度学习之处理多维特征的输入

我们首先来看一个糖尿病的数据集&#xff1a; 在数据集中&#xff0c;我们称每一行叫做sample&#xff0c;表示一个样本&#xff0c;称每一列是feature&#xff0c;也就是特征在数据库里面这就是一个关系表&#xff0c;每一行叫做记录&#xff0c;每一列叫做字段。 每一个样本都…