【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set

这篇具有很好参考价值的文章主要介绍了【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

改造原来的哈希桶

由于要使用一个哈希桶封装出unordered_map和uordered_set,所以要对哈希桶的模版参数进行改造,由于unordered_map是kv模型,而uordered_set是k模型,所以必须在实现哈希桶的时候提供模版,在封装uordered_set和unordered_map时传入不同的模版参数。
还要要修改的是,如果同时封装出,在获得key值时,unordered_map 和 unordered_set的key是不同的,所以必须传入不同仿函数来获得key值,为了后边在可以进行key比较。

namespace HashBucket
{
	template<class T>
	class HashNode
	{
	public:
		typedef HashNode<T> Node;
		HashNode(const T& data)
			:_data(data)
			,_next(nullptr)
		{}
		T _data;
		Node* _next;
	};
	template<class K, class T, class Hash, class KeyOfT>
	class HashTable;
		
	template<class K, class T, class Hash,class KeyOfT>
	class HashTable
	{
	public:
		typedef HashNode<T> Node;
		typedef iterator<K, T, Hash, KeyOfT> iterator;
		
		iterator begin()
		{
			int i = 0;
			while (!_tables[i])
			{
				i++;
			}
			return iterator(_tables[i], this);
		}
		iterator end()
		{
			return iterator(nullptr, this);
		}
		~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)
		{
			Hash hash;
			KeyOfT kot;
			auto ret = find(kot(data));
			if (ret!=end())
			{
				return make_pair(ret, false);
			}
			if (_size == _tables.size())
			{
				size_t NewSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
				vector<Node*> NewTables;
				NewTables.resize(NewSize, nullptr);

				for (size_t i = 0; i < _tables.size(); i++)
				{
					Node* cur = _tables[i];
					if (cur)
					{
						Node* next = cur->_next;

						size_t hashi = hash(kot(cur->_data)) % _tables.size();
						cur->_next = NewTables[hashi];
						NewTables[hashi] = cur;

						cur = next;
					}
					_tables[i] = nullptr;
				}
				_tables.swap(NewTables);
			}

			size_t hashi = hash(kot(data)) % _tables.size();
			Node* NewNode = new Node(data);

			NewNode->_next = _tables[hashi];
			_tables[hashi] = NewNode;

			_size++;

			return make_pair(iterator(NewNode,this), true);
		}
				
		iterator find(const K& key)
		{
			Hash hash;
			KeyOfT kot;
			if (_tables.size() == 0)
			{
				return end();
			}
			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 earse(const K& key)
		{
			Hash hash;
			KeyOfT kot;
			size_t hashi = hash(key) % _tables.size();
			Node* prev = nullptr;
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_kv) == key)
				{
					if (cur == _tables[hashi])
					{
						_tables[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					--_size;

					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}
			return false;
		}

	private:
		vector<Node*> _tables;
		size_t _size = 0;
	};

实现时要注意的问题

1.unordered_map和unordered_set的模版参数

unordered_map中的value值传入pair<K,V>,而unordered_set中的value值和key值相同。
【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set,C++进阶,哈希算法,c++,散列表

2.KeyOfT仿函数

由于unordered_map的得到key值的方法和unordered_set获得可以值的方法不同,所以必须传入KeyOfT仿函数:

		struct MapKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
		struct MapKeyOfT
		{
			const K& operator()(const pair<K,V>& kv)
			{
				return kv.first;
			}
		};

【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set,C++进阶,哈希算法,c++,散列表

3.string类型无法取模问题

由于在使用哈希函数为除留余数法时,会对key值进行取模,但是可能有的类型不支持取模,例如string,所以我们同样使用模版来解决,此时使用类模板来解决,同时对string类型进行类模板的特化:

template<class K>
class HashFunc
{
public:
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};
template<>
class HashFunc<string>
{
public:
	size_t operator()(const string& k)
	{
		size_t val = 0;
		for (auto e : k)
		{
			val *= 131;
			val += e;
		}
		return val;
	}
};

哈希桶的迭代器实现

实现unordered_map和unordered_set的迭代器,即实现哈希桶的迭代器就可以了,最后对哈希桶的迭代器进行封装:

1.迭代器的结构

	struct iterator
	{
		typedef HashTable<K, T, Hash, KeyOfT> HT;
		typedef HashNode<T> Node;

		HT* _Pht;
		Node* _node;
	};

迭代器的成员变量为一个节点的指针,另外还需要哈希表的地址。

2.迭代器++

例如下边这个哈希桶:
【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set,C++进阶,哈希算法,c++,散列表
使用迭代器后遍历顺序是这样的。
【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set,C++进阶,哈希算法,c++,散列表
迭代器++的规则:
如果哈希表中某一处为空,就去拿表中节点,根据单链表的方式,向下遍历,直到遍历到单链表为空,为空后,继续在哈希表中查找不为空处,继续根据单链表的方式向下遍历。文章来源地址https://www.toymoban.com/news/detail-523119.html

代码实现

1.unordered_map

#pragma once
#include"hash.h"


namespace tmt
{

	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;
			}
		};
		typedef typename HashBucket::HashTable<K,pair<K,V>,Hash,MapKeyOfT>::iterator iterator;
	public:
		bool insert(const pair<K,V>& kv)
		{
			return _HT.insert(kv);
		}
		iterator begin()
		{
			return _HT.begin();
		}
		iterator end()
		{
			return _HT.end();
		}
		V& operator[](const K& key)
		{
			pair<iterator,bool> ret = _HT.insert(make_pair(key,V()));
			return ret.first->second;
		}
	private:
		HashBucket::HashTable<K, pair<K,V>, Hash ,MapKeyOfT> _HT;
	};
}

2.unordered_set

namespace tmt
{
	template<class K, class V, class Hash = HashFunc<K>>
	class unordered_set
	{
		struct MapKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
		typedef typename HashBucket::HashTable<K, K, Hash, MapKeyOfT>::iterator iterator;
	public:
		bool insert(const K& key)
		{
			return _HT.insert(key);
		}
		iterator begin()
		{
			return _HT.begin();
		}
		iterator end()
		{
			return _HT.end();
		}
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _HT.insert(make_pair(key, V()));
			return ret.first->second;
		}
	private:
		HashBucket::HashTable<K, K , Hash, MapKeyOfT> _HT;
	};
}

到了这里,关于【C++进阶】使用一个哈希桶封装出unordered_map和uordered_set的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [C++]哈希表实现,unordered_map\set封装

    目录 ​​​​​​​ 前言: 1 哈希 1.1 为什么有哈希 1.2 哈希结构 1.3 哈希冲突  2 闭散列 2.1 闭散列结点结构和位置状态表示 2.2 哈希类结构 2.3 插入 2.4 查找 2.5 删除 3 开散列 3.1 哈希表结点结构 3.2 哈希表结构 3.3 插入 3.4 查找、删除 3.5 迭代器实现 4 map和set的封装 4.1 map的封

    2024年02月08日
    浏览(31)
  • C++利用开散列哈希表封装unordered_set,unordered_map

    1.之前我们已经实现了开散列的哈希表,今天我们来用它封装unordered_set,unordered_map 2.本文的封装比利用红黑树封装set和map更加复杂 建议大家先去看我的红黑树封装set和map再来看本文 因为有很多地方跟红黑树封装set和map时是同样的思路和方法,所以本文不会太去赘述一遍 因为un

    2024年03月24日
    浏览(39)
  • 【C++】开散列哈希表封装实现unordered_map和unordered_set

    在未达成目的之前,一切具有诱惑力的事物都显得那么不堪一击 1. 在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N l o g 2 ​ N ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。 最好的查询是

    2023年04月09日
    浏览(71)
  • 【C++学习】哈希表的底层实现及其在unordered_set与unordered_map中的封装

    🎉个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生 🙈个人主页🎉:GOTXX 🐼个人WeChat:ILXOXVJE 🐼本文由GOTXX原创,首发CSDN🎉🎉🎉 🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路 🐓每日一句:如果没有特别幸运,那就请特

    2024年04月16日
    浏览(36)
  • C++STL详解(十) -- 使用哈希表封装unordered_set和unordered_map

    因为不同容器的类型不同,如果是unordered_map,V代表一个键值对,如果unordered_set,V代表Key值,而底层哈希表并不知道上层容器所要传递的V模板参数类型,为了与哈希表的模板参数区分,我们将哈希表中的V模板参数改为T. 例如: 在哈希表中当我们使用Find函数进行查找时: 如果上层传递的

    2024年02月01日
    浏览(39)
  • 改造哈希表,封装unordered_map和unordered_set

    正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能 学习网站, 通俗易懂,风趣幽默 ,忍不住分享一下给大家。点击跳转到网站。 unordered_map是存的是pair是K,V型的,而unordered_set是K型的,里面只存一个值,那我们如何利用一个数据结构将他们都封装出来呢?

    2024年02月03日
    浏览(35)
  • 【C++】unordered_set 和 unordered_map 使用 | 封装

    unordered_map官方文档 unordered_set 官方文档 set / map与unordered_set / unordered_map 使用功能基本相同,但是两者的底层结构不同 set/map底层是红黑树 unordered_map/unordered_set 底层是 哈希表 红黑树是一种搜索二叉树,搜索二叉树又称为排序二叉树,所以 迭代器遍历是有序的 而哈希表对应的

    2024年02月06日
    浏览(30)
  • C++进阶--unordered_set、unordered_map的介绍和使用

      在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2N l o g 2 ​ N ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比较次数就能够将元素找到,因此在C++11中,STL又

    2024年01月16日
    浏览(35)
  • C++ unordered_map哈希表

    leetcode: 49. 字母异位词分组 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母通常恰好只用一次。 示例 1: 输入: strs = [“eat”, “tea”, “tan”, “ate”, “

    2023年04月25日
    浏览(33)
  • 从C语言到C++_31(unordered_set和unordered_map介绍+哈希桶封装)

    目录 1. unordered_set和unordered_map 1.1 unordered_map 1.2 unordered_set 1.3 unordered系列写OJ题 961. 在长度 2N 的数组中找出重复 N 次的元素 - 力扣(LeetCode) 349. 两个数组的交集 - 力扣(LeetCode) 217. 存在重复元素 - 力扣(LeetCode) 884. 两句话中的不常见单词 - 力扣(LeetCode) 2. 实现unorder

    2024年02月13日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包