[C++随想录] 哈希之unordered_map和unordered-set的封装

1. hash模版的改变

1.1 hash类模板 头的改变


1.2 封装迭代器类

🗨️ 为什么要传那么多的参数? 为什么要有hash类的前置声明呢? 为什么要多一个哈希表指针成员变量呢?

  • 加加操作中, 虽然可以找到 桶号, 但是没有 哈希桶 是没有意义的 && 哈希表指针也是可以完成哈希桶的操作的 ⇒ 所以在 迭代器类中需要有一个哈希表指针
    由于要有哈希表指针 , 所以会用到 hash类的相关参数(T - 数据类型, KeyofT, Com - 比较逻辑) 和 相关函数(比如构造啥的)迭代器类要有足够多的参数 和 hash前置声明一下

1.2.1 构造 && 拷贝构造

  1. 构造
_iterator(Node* node,const hash<K, T, KeyofT, Com>* pht)
	:_node(node)
	, _pht(pht)
{}
  1. 用普通迭代器初始化const迭代器
_iterator(const Iterator& node)
	:_node(node._node)
	, _pht(node._pht)
{}

1.2.2. ++

有两种情况 :

  1. 当前桶还有数据 — — 返回当前桶当前位置的下一个元素即可
  2. 当前桶没有数据 — — 去找下一个有元素的桶
self& operator++()
{
	Com com;
	KeyofT kot;
	size_t hashi = com(kot(_node->_data)) % _pht->_table.size();
	
	// 当前桶还有节点
	if (_node->_next)
	{
		_node = _node->_next;
	}
	// 当前桶没有节点
	else
	{
		hashi++;

		while (hashi < _pht->_table.size())
		{
			// 找到了, 就返回
			if (_pht->_table[hashi])
			{
				_node = _pht->_table[hashi];
				return *this;
			}
			else
			{
				hashi++;
			}
		}
		
		// 说明后面的桶都没有元素了, 那就返回nullptr
		_node = nullptr;

	}

	return *this;
}

1.2.3. 其他运算符重载

  1. operator==
bool operator==(const self& it)
{
	return _node == it._node;
}
  1. operator!=
bool operator!=(const self& it)
{
	return _node != it._node;
}
  1. operator*
Ptr operator*()
{
	return _node->_data;
}
  1. operator->
Ref operator->()
{
	return &(_node->_data);
}

1.3 hash类实现普通迭代器和const迭代器

  1. 类型
typedef _iterator<K,T, T&, T*, KeyofT, Com> iterator;
typedef _iterator<K,T, const T&, const T*,KeyofT, Com> const_iterator;
  1. begin end
    begin — — 返回第一个有元素的桶的地址
    end — — 返回空指针
iterator begin()
{
	for (size_t i = 0; i < _table.size(); i++)
	{
		if (_table[i])
		{
			return iterator(_table[i], this);
		}
	}
}

iterator end()
{
	return iterator(nullptr, this);
}

const_iterator begin()const
{
	for (size_t i = 0; i < _table.size(); i++)
	{
		if (_table[i])
		{
			return const_iterator(_table[i], this);
		}
	}
}

const_iterator end()const
{
	return const_iterator(nullptr, this);
}

2. unordered_set的底层逻辑

  1. SetofT — — 提取数据中的的key
struct SetofT
{
	K operator()(const K& key)
	{
		return key;
	}
};
  1. 迭代器类型
typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator iterator;
typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator const_iterator;
  1. begin, end
iterator begin()const
{
	return _ht.begin();
}

iterator end()const
{
	return _ht.end();
}
  1. erase
bool erase(const K& key)
{
	return _ht.erase(key);
}
  1. find
iterator find(const K& key)
{
	typename hash_bucket::hash<K, K, SetofT>::iterator ret = _ht.find(key);
	iterator res = ret;
	return res;
}
  1. insert
pair<iterator, bool>& insert(const K& key)
{
	pair<hash_bucket::hash<K, K, SetofT>::iterator, bool> ret = _ht.insert(key);
	pair<iterator, bool> res = ret;
	return res;
}

3. unordered_map的底层逻辑

  1. MapofT
struct MapofT
{
	K operator()(const pair<K, V>& kv)
	{
		return kv.first;
	}
};
  1. 迭代器类型
typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::iterator iterator;
typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::const_iterator const_iterator;
  1. begin, end
iterator begin()
{
	return _ht.begin();
}

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

const_iterator begin()const
{
	return _ht.begin();
}

const_iterator end()const
{
	return _ht.end();
}
  1. erase
bool erase(const K& key)
{
	return _ht.erase(key);
}
  1. find
iterator find(const K& key)
{
	return _ht.find(key);
}
  1. insert
pair<iterator, bool> insert(const pair<const K,  V>& kv)
{
	return _ht.insert(kv);
}
  1. operator[ ]
V& operator[](const K& key)
{
	pair<iterator, bool> res = _ht.insert(make_pair(key, V()));
	return res.first->second;
}

4. 源码

4.1 hash类

#pragma once

#include<iostream>
#include<vector>

using namespace std;

namespace hash_bucket
{
	template<class T>
	struct HashData
	{
	public:
		HashData(const T& kv)
			:_data(kv)
		{}
	public:
		T _data;
		HashData<T>* _next;
	};

	template<class K>
	struct DEFAULT
	{
		size_t operator()(const K& key)
		{
			return (size_t)key;
		}
	};

	template<>
	struct DEFAULT<string>
	{
		size_t operator()(const string& key)
		{
			int res = 0;
			for (auto e : key)
			{
				res += e * 131;
			}

			return res;
		}
	};

	// 前置声明
	template<class K, class T, class KeyofT, class Com>
	struct hash;

	template<class K, class T, class Ptr, class Ref, class KeyofT, class Com>
	struct _iterator
	{
		typedef HashData<T> Node;
		typedef _iterator<K, T,Ptr, Ref, KeyofT, Com> self;
		typedef _iterator<K, T,T&, T*, KeyofT, Com> Iterator;

		Node* _node;
		const hash<K, T, KeyofT, Com>* _pht;


		_iterator(Node* node,const hash<K, T, KeyofT, Com>* pht)
			:_node(node)
			, _pht(pht)
		{}

		_iterator(const Iterator& node)
			:_node(node._node)
			, _pht(node._pht)
		{}

		self& operator++()
		{
			Com com;
			KeyofT kot;
			size_t hashi = com(kot(_node->_data)) % _pht->_table.size();

			if (_node->_next)
			{
				_node = _node->_next;
			}
			else
			{
				hashi++;

				while (hashi < _pht->_table.size())
				{
					if (_pht->_table[hashi])
					{
						_node = _pht->_table[hashi];
						return *this;
					}
					else
					{
						hashi++;
					}
				}

				_node = nullptr;

			}

			return *this;
		}

		bool operator!=(const self& it)
		{
			return _node != it._node;
		}

		Ptr operator*()
		{
			return _node->_data;
		}

		Ref operator->()
		{
			return &(_node->_data);
		}

	};

	template<class K, class T, class KeyofT, class Com = DEFAULT<K>>
	struct hash
	{
		typedef HashData<T> Node;

		// 友元
		//template<class K, class Ptr, class Ref, class T, class KeyofT, class Com>
		//friend struct _iterator;

	public:
		typedef _iterator<K,T, T&, T*, KeyofT, Com> iterator;
		typedef _iterator<K,T, const T&, const T*,KeyofT, Com> const_iterator;

	public:

		iterator begin()
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				if (_table[i])
				{
					return iterator(_table[i], this);
				}
			}
		}

		iterator end()
		{
			return iterator(nullptr, this);
		}

		const_iterator begin()const
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				if (_table[i])
				{
					return const_iterator(_table[i], this);
				}
			}
		}

		const_iterator end()const
		{
			return const_iterator(nullptr, this);
		}

		hash()
		{
			_table.resize(4, nullptr);
		}

		iterator find(const K& key)
		{
			size_t hashi = com(key) % _table.size();
			Node* cur = _table[hashi];
			while (cur)
			{
				if (com(kot(cur->_data)) == com(key))
				{
					return iterator(cur, this);
				}

				cur = cur->_next;
			}

			return iterator(nullptr, this);
		}

		pair<iterator, bool> insert(const T& kv)
		{
			iterator res = find(kot(kv));
			if (res != end())
			{
				// 不要返回空, 要返回重复值的指针, 以便与后面的 [] 来进行修改value
				return make_pair(res, false);
			}

			// 扩容逻辑
			if (_sz == _table.size())
			{
				vector<Node*> new_table;
				new_table.resize(_table.size() * 2, nullptr);
				for (size_t i = 0; i < _table.size(); i++)
				{
					Node* cur = _table[i];

					while (cur)
					{
						Node* next = cur->_next;

						size_t hashi = com(kot(cur->_data)) % new_table.size();
						cur->_next = new_table[hashi];
						new_table[hashi] = cur;

						cur = next;
					}
				}

				_table.swap(new_table);
			}

			// 插入逻辑
			size_t hashi = com(kot(kv)) % _table.size();
			Node* newnode = new Node(kv);

			newnode->_next = _table[hashi];
			_table[hashi] = newnode;

			++_sz;
			return make_pair(iterator(_table[hashi], this), true);
		}

		bool erase(const K& key)
		{
			Node* res = find(key);
			if (res == nullptr)
			{
				return false;
			}
			else
			{
				size_t hashi = com(key) % _table.size();
				Node* cur = _table[hashi];
				Node* prev = nullptr;
				while (cur)
				{
					if (cur->_data.first == key)
					{
						if (prev == nullptr)
						{
							_table[hashi] = cur->_next;
						}
						else
						{
							prev->_next = cur->_next;
						}

					}

					prev = cur;
					cur = cur->_next;
				}

				--_sz;
				delete cur;
			}

			return true;
		}

		void print()
		{
			for (int i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				printf("[%d]->", i);
				while (cur)
				{
					printf("%d", cur->_data.first);
					cur = cur->_next;
				}
				cout << "NULL" << endl;
			}
			cout << endl;
		}

	public:
		vector<Node*> _table;
		size_t _sz = 0;
		Com com;
		KeyofT kot;
	};
}

4.2 unordered_set类

#pragma once

#include"hash_bucket.h"
#include<iostream>

using namespace std;

namespace muyu
{
	template<class K>
	class unordered_set
	{
		struct SetofT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};

	public:
		typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator iterator;
		typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator const_iterator;

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

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

		pair<iterator, bool>& insert(const K& key)
		{
			pair<hash_bucket::hash<K, K, SetofT>::iterator, bool> ret = _ht.insert(key);
			pair<iterator, bool> res = ret;
			return res;
		}

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

		iterator find(const K& key)
		{
			typename hash_bucket::hash<K, K, SetofT>::iterator ret = _ht.find(key);
			iterator res = ret;
			return res;
		}

	private:
		hash_bucket::hash<K, K, SetofT> _ht;
	};
}

4.3 unordered_map类

#pragma once

#include"hash_bucket.h"
#include<iostream>

using namespace std;

namespace muyu
{
	template<class K, class V>
	class unordered_map
	{
		struct MapofT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};

	public:
		typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::iterator iterator;
		typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::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 pair<const K,  V>& kv)
		{
			return _ht.insert(kv);
		}

		V& operator[](const K& key)
		{
			pair<iterator, bool> res = _ht.insert(make_pair(key, V()));
			return res.first->second;
		}

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

		iterator find(const K& key)
		{
			return _ht.find(key);
		}

	private:
		hash_bucket::hash<K, pair<const K, V>, MapofT> _ht;
	};
}

爱此倚栏干,谁同寓目闲。
轻阴弄晴日,秀色隐空山。
岛树萧疏外,征帆杳霭间。
予虽江上老,心羡白云还。
— — 岳飞 <题池州翠光寺>

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨 子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值