C++语法(23)-- 模拟实现unordered_set和unordered_map

news/2024/12/29 22:47:29/


C++语法(22)---- 哈希表的闭散列和开散列_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130436178?spm=1001.2014.3001.5501

1.重写HashTable

由于此时我们的实现与map跟set差不多,所以需要进行调整

1.重写节点

节点通过unordered_set和unordered_map传入的东西来构造是Value类型还是pair<K,V>类型

template<class T>
struct HashNode
{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){}
};

2.重写哈希表

1.首先,一定要通过Key值查找对应的值,那么我们需要设置一个模板为K

2.我们还要传入哈希元素节点,设置模板为T(与上面一致)

3.将T的值进行哈希映射的Hash仿函数,该函数应该在unordered层传入,因为我们也不知道要映射到位置上的是什么

4.还有一个是与map和set实现一样的仿函数,用于区分到底是unordered_map还是unordered_set中的Key值的比较,该模板命名为KeyOfT

template<class K, class T, class Hash, class KeyOfT>
class HashTable
{typedef HashNode<T> Node;
public:HashTable():_n(0){_table.resize(10);}~HashTable(){//省略}bool Insert(const T& data){//需要注意获取哈希映射的方式//需要用到hash转换k为对应的int再进行操作KeyOfT kot;if (Find(kot(data)) != nullptr)return false;if (_n == _table.size()){//省略怎么扩容的}//需要注意获取哈希映射的方式//需要用到上层传来的KeyOfT使得data变成可以被哈希映射的值size_t hashi = kot(data) % _table.size();//省略怎么插入的}Node* Find(const K& k){//需要注意获取哈希映射的方式//需要用到hash转换k为对应的int再进行操作size_t hashi = Hash()(k) % _table.size(); //省略怎么找的}bool Erase(const K& k){//需要注意获取哈希映射的方式//需要用到hash转换k为对应的int再进行操作size_t hashi = Hash()(k) % _table.size(); //省略怎么删除的}private:vector<Node*> _table;size_t _n = 0;
};

2.unordered初步实现

1.unordered_set

对于set而言,传入的直接就是Key,那么SetOfT仿函数返回的就是key

namespace MY
{template<class K,class Hash = HashFunc<K>>class unordered_set{struct SetOfT{const K& operator()(const K& key){return key;}};private:buckethash::HashTable<K, K, Hash, SetOfT> _ht;};
}

2.unordered_map

对于map而言,传入的是pair,那么MapOfT仿函数返回的就是pair的first

namespace MY
{template<class K, class V, class Hash = HashFunc<K>>class unordered_map{struct MapOfT{const K& operator()(const pair<const K, V>& key){return key.first;}};private:buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT> _ht;};
}

3. 哈希表的迭代器

template<class K, class T, class Hash, class KeyOfT>
struct __HTIterator
{typedef HashNode<T> Node;typedef __HTIterator<K, T, Hash, KeyOfT> Self;typedef HashTable<K, T, Hash, KeyOfT> HT;Node* _node;HT* _ht;
};

我们需要算到开始的位置,所以一定要传入哈希表的地址,随后访问到哈希表的tables。

迭代器的简单函数

__HTIterator(Node* node,HT* ht):_node(node),_ht(ht)
{}T operator*()
{return _node->_data;
}T& operator->()
{return &_node->_data;
}bool operator != (const Self& s) const
{return _node != s._node;
}

重写++的实现

首先我们找到下一个位置有两种情况

1.指针往下就是下一个数

2.整个桶走完了,我们要找下一个桶有数据的位置

Self& operator++()
{if (_node->_next){_node = _node->_next;}else{KeyOfT kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % (_ht->_table.size());hashi++;while (hashi < _ht->_table.size()){if (_ht->_table[hashi]){_node = _ht->_table[hashi];break;}else++hashi;}if (hashi == _ht->_table.size()){_node = nullptr;}}return *this;
}

因为迭代器用到了哈希表,但是我将迭代器写在了哈希表的前面,所以在此之前还得先定义哈希表的前置声明

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

 4.哈希表的迭代器形式

1.迭代器怎么才使用_table

由于哈希表中的table是私有对象,而迭代器需要访问table,那么就要将迭代器设置为哈希表的友元。

template<class K, class T, class Hash, class KeyOfT>
class HashTable
{typedef HashNode<T> Node;template<class K, class T, class Hash, class KeyOfT>friend struct __HTIterator; //友元public:typedef __HTIterator<K, T, Hash, KeyOfT> iterator;
private:vector<Node*> _table;size_t _n = 0;
};

2.哈希表中的迭代器

需要注意的是,在迭代器中,构造函数为:

__HTIterator(Node* node,HT* ht):_node(node),_ht(ht)
{}

所以哈希表的函数返回包括迭代器内容的,一律需要构造迭代器返回。

_node:就是生成的节点的地址,该地址就是节点的指针,这个好获得

_ht:为哈希表的地址,那么我们在哈希表的类中,本身的对象就是_ht,我们只需要返回this

iterator begin()
{for (size_t i = 0; i < _table.size(); i++){if (_table[i] != nullptr)return iterator(_table[i], this);}return iterator(nullptr, this);
}iterator end()
{return iterator(nullptr, this);
}
iterator Find(const K& k)
{size_t hashi = Hash()(k) % _table.size();Node* cur = _table[hashi];KeyOfT kot;while (cur){if (kot(cur->_data) == k)return iterator(cur, this);elsecur = cur->_next;}return iterator(nullptr,this);
}bool Erase(const K& k)
{size_t hashi = Hash()(k) % _table.size();Node* cur = _table[hashi];Node* prev = nullptr;while (cur){if (cur->_kv.first == k){if (cur == _table[hashi])_table[hashi] = cur->_next;elseprev->_next = cur->_next;delete cur;_n--;return true;}prev = cur;cur = cur->_next;}return false;
}

因为需要实现map的operator[],因此insert的重写是返回一个pair类型,first是迭代器,second是bool。

pair<iterator, bool> Insert(const T& data)
{KeyOfT kot;iterator it = Find(kot(data));if (it != end())return make_pair(it, false);if (_n == _table.size()){vector<Node*> newTable;newTable.resize(2 * _table.size(),nullptr);for (int i = 0; i < _table.size(); i++){Node* cur = _table[i];while (cur){Node* next = cur->_next;size_t hashi = Hash()(kot(cur->_data)) % newTable.size();cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}_table[i] = nullptr;}_table.swap(newTable);}size_t hashi = Hash()(kot(data)) % _table.size();Node* newnode = new Node(data);newnode->_next = _table[hashi];_table[hashi] = newnode;_n++;return make_pair(iterator(newnode, this), true);
}

5.unordered_map和unordered_set

	template<class K, class V, class Hash = HashFunc<K>>class unordered_map{struct MapOfT{const K& operator()(const pair<const K, V>& key){return key.first;}};public:typedef typename buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}iterator Find(const K& k){return _ht.Find(k);}bool Erase(const K& k){return _ht.Erase(k);}pair<iterator, bool> insert(const pair<const K, V>& data){return _ht.Insert(data);}V& operator[](const K& key){pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));return ret.first->second;}private:buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT> _ht;};
	template<class K,class Hash = HashFunc<K>>class unordered_set{struct SetOfT{const K& operator()(const K& key){return key;}};public:typedef typename buckethash::HashTable<K, K, Hash, SetOfT>::iterator iterator;iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}iterator Find(const K& k){return _ht.Find(k);}bool Erase(const K& k){return _ht.Erase(k);}pair<iterator, bool> insert(const K& key){return _ht.Insert(key);}private:buckethash::HashTable<K, K, Hash, SetOfT> _ht;};

http://www.ppmy.cn/news/207136.html

相关文章

【MCS-51单片机汇编语言】期末复习总结④——求定时器初值(题型四)

文章目录 重要公式T~机器~ 12 / ∫~晶振~(2^n^ - X) * T~机器~ T~定时~ 工作方式寄存器TMOD常考题型例题1题解方式0方式1 关于定时器的常考题目为已知晶振 ∫ 、定时时间&#xff0c;求定时器初值。 重要公式 T机器 12 / ∫晶振 (2n - X) * T机器 T定时 其中n为定时器位数…

磨刀霍霍向Gamer 老黄发布英伟达甜点级显卡RTX 2060

雷锋网消息&#xff0c;CES前夕&#xff0c;英伟达发布了基于图灵架构的显卡GeForce RTX 2060&#xff0c;英伟达CEO黄仁勋表示&#xff0c;“桌面游戏玩家要求很高&#xff0c;RTX 2060设定了新标准 - 无与伦比的价格&#xff0c;非凡的性能和实时光线追踪&#xff0c;模糊了电…

yolo过程中的小知识点

不会使用vim编辑器就使用文本编辑器&#xff0c;即不使用命令 sudo vim /etc/apt/sources.list而改用 sudo gedit /etc/apt/sources.list打开标定软件 python3 labelImg.pymAP mean average precision多个类别物体检测中&#xff0c;每一个类别都可以根据recall和precision绘…

4000元性价比主机

转载自公众号&#xff1a;FUN科技 当然小伙伴们准备去上学的同时&#xff0c;肯定也会有考虑装机的需求&#xff0c;所以这次就开学的季节&#xff0c;给囊中羞涩的同学们推荐一下IntelNVIDIA的性价比配置吧。 image 从前段时间开始淘宝爆款CPU I5 8400/8500 散片又又又开始涨价…

游戏计算机性能要求,解答玩大型游戏的电脑配置

玩电脑大型游戏对于配置有什么要求呢?大家都知道,电脑分为硬件系统和软件系统,而硬件是电脑的基础,大型游戏又属于高端级别的游戏,对于硬件的选择更要多加考虑。我给大家带来了一些大型游戏所需电脑配置,大家可以参考一下 随着网络的发展,大家越来越不开电脑,工作学习娱…

游戏计算机性能要求吗,玩电脑大型游戏对于配置有什么要求

玩电脑大型游戏对于配置有什么要求呢?大家都知道&#xff0c;电脑分为硬件系统和软件系统&#xff0c;而硬件是电脑的基础&#xff0c;大型游戏又属于高端级别的游戏&#xff0c;对于硬件的选择更要多加考虑。我给大家带来了一些大型游戏所需电脑配置&#xff0c;大家可以参考…

win8配置_【装机帮扶站】第382期:甜点级真的甜!4000价位GTX1660配置推荐!

【提示】 我们之前推荐的昂达H310C-CD3/SD3、影驰B360M-M.2等主板目前官网都已经放出更新BIOS&#xff0c;DOS下刷新后可以支持九代处理器。可以看出这次同德系板子应该是统一更新的&#xff0c;虽然比其他品牌晚了近半年&#xff0c;但至少是更新了~~ 【前言】 虽然这一代中端…

2021双十二组一套电脑配置的攻略

2021双十二组一套电脑配置攻略 前言 昨天下午写了两篇文章&#xff1a;《XSX和PS5对标的电脑配置&#xff08;2021年12月10日分析&#xff09;》和《关于我家的五台主机的升级计划》&#xff0c;发现电脑配置中机箱、电源、散热、内存条、硬盘可以固定下来&#xff0c;然后CP…