C++ STL unordered_map/set 实现

大家看这篇博客前,需要先知道哈希表的原理,这篇博客只是对哈希表进行封装。如果没有看过的可以看看我写的这篇博客:C++哈希表。同时读者需要知道STL的unordered_map/set的用法

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<variant>
#include<map>
#include<set>
#include<type_traits>
namespace dgj {
	template<class T>
	struct hash {
		size_t operator()(const T& x)const {
			return x;
		}
	};
	template<>
	struct hash<std::string> {
		size_t operator()(const std::string& str)const{
			size_t pos = 0;
			for (auto ch : str) {
				pos = pos * 131 + ch;
			}
			return pos;
		}
	};
	template<class ...Args>
	struct overloads:public Args... {
		using Args::operator() ...;
	};
	template<class ...Args>
	overloads(Args...)->overloads<Args...>;

	template<class T,class hashfunc=hash<T>>
	class Hash {
		using self = Hash<T, hashfunc>;
		//哈希映射
		size_t hashMap(size_t hashNum, size_t capacity)const{
			if (!capacity)return 0;
			//如果是2的幂就走优化
			if (!(capacity & (capacity - 1))) {
				return hashNum & (capacity - 1);
			}
			else {
				return hashNum % capacity;
			}
		}
		size_t findNextPowerOfTwo(size_t n) {
			if (n == 0) {
				return 1;
			}
			// 位运算技巧:将n的最高位之后的位都置1,然后加1
			n--;
			n |= n >> 1;
			n |= n >> 2;
			n |= n >> 4;
			n |= n >> 8;
			n |= n >> 16;
			// 64位系统需补充n |= n >> 32;
			if constexpr (sizeof(int*) == 8) {
				n |= n >> 32;
			}
			return n + 1;
		}
	public:
		Hash()  {
			_table.resize(_buckets);
		}
		void insert(const T& x) {
			size_t pos = hashMap(_hash(x), _buckets);
			/*std::visit(Vist(x, pos,_table), _table[pos]);*/
			std::visit(overloads(
				[&](std::list<T>& ls) {
					ls.emplace_back(x);
					if (ls.size() >= 8) {
						std::set<T>st(ls.begin(), ls.end());
						_table[pos] = std::move(st);
					}
				},
				[&](std::set<T>& st) {
					st.emplace(x);
				}
			), _table[pos]);
			++_size;
			if (load_factor() > _max_load_factor) {
				reserve(_size + 1); // 扩容到能容纳_size+1个元素的大小
			}
		}
		bool find(const T& x)const {
			size_t pos = hashMap(_hash(x), _buckets);
			return std::visit(overloads{
						[&](const std::list<T>& ls) {return std::find(ls.begin(), ls.end(), x) != ls.end(); },
						[&](const std::set<T>& st) {return static_cast<bool>(st.count(x)); }
				}
				,_table[pos]
			);
		}

		bool erase(const T& x) {
			size_t pos = hashMap(_hash(x), _buckets);
			return std::visit(overloads{
					[&](std::list<T>& num) {
						auto it = std::find(num.begin(), num.end(), x);
						if (it == num.end())return false;
						num.erase(it);
						_size--;
						return true;
					},
					[&](std::set<T>& num) {
						auto it = num.find(x);
						if (it == num.end())return false;
						num.erase(it);
						_size--;
						return true;
					}
					}, _table[pos]);
			
		}
		void swap(self& x) {
			std::swap(x._size, _size);
			std::swap(x._buckets, _buckets);
			std::swap(x._table, _table);
			std::swap(x._hash, _hash);
			std::swap(_max_load_factor, x._max_load_factor);
		}
	public:
		float max_load_factor()const {
			return _max_load_factor;
		}
		void max_load_factor(float factor) {
			_max_load_factor = factor;
		}
		float load_factor()const {
			return _size / (1.0f * _buckets);
		}
		void reserve(size_t size) {
			size_t reSize = findNextPowerOfTwo(size / _max_load_factor);
			rehash(reSize);
		}
		void rehash(size_t size) {
			size_t reSize = findNextPowerOfTwo(size);
			if (reSize <= _buckets)return;
			self newHash;
			newHash._buckets = reSize;
			newHash._max_load_factor = _max_load_factor;
			newHash._table.resize(reSize);
			for (auto& num : _table) {
				std::visit(overloads{
						[&](auto&& k) {
							for (auto n : k) {
								newHash.insert(n);
							}
						}
					}, num);
			}
			swap(newHash);

		}
		void clear() {
			_size = 0;
			_buckets = _default_bucket;
			_table.resize(_default_bucket);
			_max_load_factor = _default_factor;
			for (auto& num : _table) {
				std::visit(overloads{
					[](auto&& k) {
						k.clear();
					}
				}, num);
			}
		}

	public:
		size_t size()const {
			return _size;
		}

		size_t bucket_count() {
			return _buckets;
		}
		size_t bucket_size(size_t n) {
			if (n >= _buckets)return -1;
			return std::visit(overloads([](auto&& num) {return num.size(); }), _table[n]);
		}
	private:	
		inline const static size_t _default_bucket = 8;
		inline const static float _default_factor = 1.0;
		float _max_load_factor = _default_factor;
		size_t _size = 0;
		size_t _buckets = _default_bucket;
		std::vector < std::variant<std::list<T>,std::set<T>> > _table;
		hashfunc _hash;
	};
}

这是在C++哈希表博客里面最后实现的代码,他已经可以作为哈希表使用了,只是需要封装接口,加上迭代器。但是这个出现第一个问题

模板统一K-V和K存储

问题一

我们上面只是实现了存储K的哈希表,那么我们该如何实现一个存储K-V的哈希表呢?很简单,模板加上K-V,把插入换成K-V,然后最终存V就行了。但是和K的哈希表高度相似,这太不优雅了

我们发现查找K-V或者是K的哈希表都是通过K来查找的,只是最后存储的不同,一个存储K一个存储V。这里我们也可以理解K哈希表可以看成K-K的哈希表,即K-V的特殊情况。

但是K-V只存V是否可以呢?查找的时候,我们是用K去比较的,但是底层只存了,V,那么K不知道和谁比了,因此要存储K-V结构

问题二

我们查找删除等操作,用K去找,和最后的V怎么比较?因此我们需要独立出来一个比较函数,对于K的哈希表我们直接返回K,对于K-V的哈希表我们要返回第一个K。

这里我们传入一个GetK的仿函数来区分处理

问题三

set怎么存储V?,到时候查找的时候只要比较K就行,因此还需要给set传入一个compare的仿函数

这里还得传GetK的仿函数,不然不知道怎么获取K

问题四

我怎么拿K去找set<V>,创建一个V,V的first给K,second给个默认值即可,然后传进去就行了

实现

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<variant>
#include<map>
#include<set>
#include<type_traits>
namespace dgj {
	template<class K>
	struct hash {
		size_t operator()(const K& x)const {
			return x;
		}
	};
	template<>
	struct hash<std::string> {
		size_t operator()(const std::string& str)const{
			size_t pos = 0;
			for (auto ch : str) {
				pos = pos * 131 + ch;
			}
			return pos;
		}
	};
	template<class ...Args>
	struct overloads:public Args... {
		using Args::operator() ...;
	};
	template<class ...Args>
	overloads(Args...)->overloads<Args...>;

	template<class K,class V,class GetK, class hashfunc = hash<K>>
	class Hash {
		using self = Hash<K,V, GetK,hashfunc>;
		size_t hashMap(size_t hashNum, size_t capacity)const{
			if (!capacity)return 0;
			if (!(capacity & (capacity - 1))) {
				return hashNum & (capacity - 1);
			}
			else {
				return hashNum % capacity;
			}
		}
		size_t findNextPowerOfTwo(size_t n) {
			if (n == 0) {
				return 1;
			}
			n--;
			n |= n >> 1;
			n |= n >> 2;
			n |= n >> 4;
			n |= n >> 8;
			n |= n >> 16;
			if constexpr (sizeof(int*) == 8) {
				n |= n >> 32;
			}
			return n + 1;
		}
	public:
		Hash()  {
			_table.resize(_buckets);
		}
		void insert(const K& key,const V&value) {
			size_t pos = hashMap(_hash(key), _buckets);
			std::visit(overloads(
				[&](std::list<V>& ls) {
					ls.emplace_back(value);
					if (ls.size() >= 8) {
						std::set< V, _setcompare<V, GetK>>st(ls.begin(), ls.end());
						_table[pos] = std::move(st);
					}
				},
				[&](std::set< V, _setcompare<V, GetK>>& st) {
					st.emplace(value);
				}
			), _table[pos]);
			++_size;
			if (load_factor() > _max_load_factor) {
				reserve(_size + 1); 
			}
		}
		bool find(const K& key)const {
			size_t pos = hashMap(_hash(key), _buckets);
			return std::visit(overloads{
						[&](const std::list<V>& ls) {
							for (const V& v : ls) {
								if (_getk(v) == key) {
									return true;
								}
							}
							return false;
						},
						[&](const std::set< V, _setcompare<V, GetK>>& st) {return static_cast<bool>(st.count({key,V().second})); }
				}
				,_table[pos]
			);
		}
		bool erase(const K& key) {
			size_t pos = hashMap(_hash(key), _buckets);
			return std::visit(overloads{
					[&](std::list<V>& num) {
						for (auto it = num.begin(); it != num.end(); ++it) {
							if (_getk(*it) == key) {
								num.erase(it);
								_size--;
								return true;
							}
						}
						return false;
					},
					[&](std::set< V, _setcompare<V, GetK>>& num) {
						V pr = {key,V().second};
						auto it = num.find(pr);
						if (it == num.end())return false;
						num.erase(it);
						_size--;
						return true;
					}
					}, _table[pos]);
		}
		void swap(self& x) {
            if (&x == this)return;
			std::swap(x._size, _size);
			std::swap(x._buckets, _buckets);
			std::swap(x._table, _table);
			std::swap(x._hash, _hash);
			std::swap(_max_load_factor, x._max_load_factor);
			std::swap(x._getk, _getk);
		}
	public:
		float max_load_factor()const {
			return _max_load_factor;
		}
		void max_load_factor(float factor) {
			_max_load_factor = factor;
		}
		float load_factor()const {
			return _size / (1.0f * _buckets);
		}
		void reserve(size_t size) {
			size_t reSize = findNextPowerOfTwo((size*1.0)/ _max_load_factor);
			rehash(reSize);
		}
		void rehash(size_t size) {
			size_t reSize = findNextPowerOfTwo(size);
			if (reSize <= _buckets)return;
			self newHash;
			newHash._buckets = reSize;
			newHash._max_load_factor = _max_load_factor;
			newHash._table.resize(reSize);
			for (auto& num : _table) {
				std::visit(overloads{
						[&](auto&& k) {
							for (auto n : k) {
								newHash.insert(_getk(n), n);
							}
						}
					}, num);
			}
			swap(newHash);
		}
		void clear() {
			_size = 0;
			_buckets = _default_bucket;
			_table.resize(_default_bucket);
			_max_load_factor = _default_factor;
			for (auto& num : _table) {
				std::visit(overloads{
					[](auto&& k) {
						k.clear();
					}
				}, num);
			}
		}

	public:
		size_t size()const {
			return _size;
		}

		size_t bucket_count() {
			return _buckets;
		}
		size_t bucket_size(size_t n) {
			if (n >= _buckets)return -1;
			return std::visit(overloads([](auto&& num) {return num.size(); }), _table[n]);
		}
	private:	
		template<class V,class GetK>
		struct _setcompare {
			bool operator()(const V& x, const V& y)const {
				return _getk(x) < _getk(y);
			};
			GetK _getk;
		};
		//增加获取k的仿函数
		GetK _getk;
		inline const static size_t _default_bucket = 8;
		inline const static float _default_factor = 1.0;
		float _max_load_factor = _default_factor;
		size_t _size = 0;
		size_t _buckets = _default_bucket;
		std::vector < std::variant < std::list<V>, std::set < V,_setcompare<V, GetK> >> > _table;
		hashfunc _hash;
	};
}

问题五

Pred模板参数问题,Pred是为了传operator==的,但是哈希表底层会转set,set又是用operator<的,那岂不冲突了吗?这里说明一下unordered_map/set底层并不会转set,因此不传operator<。所以我们可以删除set的转换

实现

删除set那么就简单多了

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<variant>
#include<map>
#include<set>
#include<type_traits>


namespace dgj {
	template<class K>
	struct hashfunc {
		size_t operator()(const K& x)const {
			return x;
		}
	};
	template<>
	struct hashfunc<std::string> {
		size_t operator()(const std::string& str)const {
			size_t pos = 0;
			for (auto ch : str) {
				pos = pos * 131 + ch;
			}
			return pos;
		}
	};

	template<class K>
	struct predfunc {
		bool operator()(const K& x, const K& y) {
			return x == y;
		}
	};
}



namespace dgj {
	template<class K,class V,class GetK, class hashfunc,class predfunc>
	class Hash {
		using self = Hash<K,V, GetK,hashfunc, predfunc>;
		size_t hashMap(size_t hashNum, size_t capacity)const{
			if (!capacity)return 0;
			if (!(capacity & (capacity - 1))) {
				return hashNum & (capacity - 1);
			}
			else {
				return hashNum % capacity;
			}
		}
		size_t findNextPowerOfTwo(size_t n) {
			if (n == 0) {
				return 1;
			}
			n--;
			n |= n >> 1;
			n |= n >> 2;
			n |= n >> 4;
			n |= n >> 8;
			n |= n >> 16;
			if constexpr (sizeof(int*) == 8) {
				n |= n >> 32;
			}
			return n + 1;
		}
	public:
		Hash()  {
			_table.resize(_buckets);
		}
		void insert(const K& key,const V&value) {
			size_t pos = hashMap(_hash(key), _buckets);
			if (_table[pos].end() != std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; })) {
				return;
			}
			_table[pos].emplace_back(value);
			++_size;
			if (load_factor() > _max_load_factor) {
				reserve(_size + 1); 
			}
		}
		template<class...Args >
		void emplace(Args&&...args) {
			std::tuple<Args&&...>tp = std::forward_as_tuple(std::forward<Args>(args)...);
			const K& key = std::get<0>(tp);
			size_t pos = hashMap(_hash(key), _buckets);
			if (_table[pos].end() != std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; }))return;
			if constexpr (sizeof...(Args) == 2) {
				// 场景1:参数是键+值(各1个参数),直接原位构造
				_table[pos].emplace_back(
					std::forward<decltype(std::get<0>(tp))>(std::get<0>(tp)),
					std::forward<decltype(std::get<1>(tp))>(std::get<1>(tp))
				);
			}
			else {
				// 场景2:参数是键+值的多参数(比如emplace(1, 5, 'a')),需分段构造(后续优化)
				// 这里先给出错误提示,或扩展为通用分段构造逻辑
				static_assert(sizeof...(Args) == 2, "仅支持键+值各一个参数的场景,多参数请使用分段构造");
            
			}
            if (load_factor() > _max_load_factor) {
	            reserve(_size + 1);
            }
		}
		bool find(const K& key)const {
			size_t pos = hashMap(_hash(key), _buckets);
			return _table[pos].end()!=std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
		}
		size_t count(const K& key)const {
			if (find(key))return 1;
			else return 0;
		}
		bool erase(const K& key) {
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return _getk(v) == key; });
			if (it != _table[pos].end()) {
				_table[pos].erase(it);
				--_size;
				return true;
			}
			return false;
		}
		void swap(self& x) {
			if (&x == this)return;
			std::swap(x._size, _size);
			std::swap(x._buckets, _buckets);
			std::swap(x._table, _table);
			std::swap(x._hash, _hash);
			std::swap(_max_load_factor, x._max_load_factor);
			std::swap(x._getk, _getk);
		}
	public:
		float max_load_factor()const {
			return _max_load_factor;
		}
		void max_load_factor(float factor) {
			_max_load_factor = factor;
		}
		float load_factor()const {
			return _size / (1.0f * _buckets);
		}
		void reserve(size_t size) {
			size_t reSize = findNextPowerOfTwo((size*1.0)/ _max_load_factor);
			rehash(reSize);
		}
		void rehash(size_t size) {
			size_t reSize = findNextPowerOfTwo(size);
			if (reSize <= _buckets)return;
			self newHash;
			newHash._buckets = reSize;
			newHash._max_load_factor = _max_load_factor;
			newHash._table.resize(reSize);
			for (auto& num : _table) {
				for (auto n : num) {
					newHash.insert(_getk(n), n);
				}
			}
			swap(newHash);
		}
		void clear() {
			_size = 0;
			_buckets = _default_bucket;
			_table.resize(_default_bucket);
			_max_load_factor = _default_factor;
			for (auto& num : _table) {
				num.clear();
			}
		}

	public:
		size_t size()const {
			return _size;
		}
		bool empty()const {
			return !_size;
		}
		size_t bucket_count()const {
			return _buckets;
		}
		size_t max_bucket_count()const {
			return _table.size();
		}
		size_t bucket_size(size_t n)const {
			if (n >= _buckets)return -1;
			return _table[n].size();
		}
	private:	
		//增加获取k的仿函数
		GetK _getk;
		inline const static size_t _default_bucket = 8;
		inline const static float _default_factor = 1.0;
		float _max_load_factor = _default_factor;
		size_t _size = 0;
		size_t _buckets = _default_bucket;
		std::vector <std::list<V>> _table;
		hashfunc _hash;
	};
}

顺便加了count,empty,emplace

实现unordered_map/set

那还说啥了,直接套hash类就行了

cpp 复制代码
namespace dgj {
	template<class K,class T, class HashFunc = hashfunc<K>, class PredFunc = predfunc<K>>
	class unorderedMap {
		struct GetK {
			const K& operator()(const T& t) {
				return t.first;
			}
		};
		using self = unorderedMap<K,T,HashFunc, PredFunc>;
	public:
		bool empty()const { return _hash.empty(); }
		size_t size()const { return _hash.size(); }
		size_t count(const K& k) { return _hash.count(k); }
		template<class...Args>
		void emplace(Args&& args) { _hash.emplace(std::forward<Args>(args)...); }
		void insert(const K& k,const K&v) { _hash.insert(k, v); }
		void erase(const K& k) { _hash.erase(k); }
		void clear() { _hash.clear(); }
		void swap(self& x) { _hash.swap(x._hash); }
		size_t bucket_count()const { return _hash.bucket_count(); }
		size_t max_bucket_count()const { return _hash.max_bucket_count(); }
		size_t bucket_size(size_t pos)const { return _hash.bucket_size(pos); }
		float load_factor()const { return _hash.load_factor(); }
		void max_load_factor(float f) { return _hash.max_load_factor(f); }
		float max_load_factor()const { return _hash.max_load_factor(); }
		void rehash(size_t size) { return _hash.rehash(size); }
		void reserve(size_t size) { return _hash.reserve(size); }
	private:
		Hash<K, T, GetK, HashFunc, PredFunc>_hash;
	};
}

namespace dgj {
	template<class K,class HashFunc=hashfunc<K>,class PredFunc=predfunc<K>>
	class unorderedSet{
		template<class K>
		struct getk(const V& v) {
			return v;
		}
		using self = unorderedSet<K, HashFunc, PredFunc>;
	public:
		bool empty()const {return _hash.empty();}
		size_t size()const {return _hash.size();}
		size_t count(const K& k) {return _hash.count(k);}
		template<class...Args>
		void emplace(Args&& args) {_hash.emplace(std::forward<Args>(args)...);}
		void insert(const K& k) {_hash.insert(k, k);}
		void erase(const K&k) {_hash.erase(k);}
		void clear() {_hash.clear();}
		void swap(self&x) {_hash.swap(x._hash);}
		size_t bucket_count()const {return _hash.bucket_count();}
		size_t max_bucket_count()const {return _hash.max_bucket_count();}
		size_t bucket_size(size_t pos)const {return _hash.bucket_size(pos);}
		float load_factor()const {return _hash.load_factor();}
		void max_load_factor(float f) {return _hash.max_load_factor(f);}
		float max_load_factor()const {return _hash.max_load_factor();}
		void rehash(size_t size) {return _hash.rehash(size);}
		void reserve(size_t size) {return _hash.reserve(size);}
	private:
		Hash<K, K, getk, HashFunc, PredFunc>_hash;
	};
}

迭代器实现

底层主要存储对应桶的指针,然后是桶下标和当前桶的迭代器(这里用的是list的迭代器)。那么就可以实现了。

++就是先走底层list迭代器,如果到末尾了,跳到下一个非空的桶里。

==先比较是否是一个桶再比较是否是一个list迭代器

cpp 复制代码
template<class K,class V,class Ptr,class Ref>
class HashIterator {
using Self = HashIterator<K, V, Ptr, Ref>;
using ReSelf = Self&;
using PtrSelf = Self*;
public:
	HashIterator(const Self& s) 
		:_bucket_pos(s._bucket_pos),
		_it(s._it),
		_table(s._table)
	{
	}
	HashIterator(size_t pos, std::list<V>::iterator it, std::vector <std::list<V>>* table)
		:_bucket_pos(pos),
		_it(it),
		_table(table)
	{
	}

	Ref operator*() {
		return *_it;
	}
	Ptr operator->() {
		return &(*_it);
	}
	ReSelf operator=(Self& x) {
		if (this != &x) {
			_bucket_pos = x._bucket_pos;
			_it = x._it;
			_table = x._table;
		}
		return *this;
	}
	ReSelf operator++() {
		++_it;
		while (_it == (*_table)[_bucket_pos].end()) {
			_it = (*_table)[++_bucket_pos].begin();
			if (_bucket_pos==_table->size()-1&&_it==_table->back().end())break;
		}
		return *this;
	}
	bool operator ==(const Self&it)const {
		return _table == it._table && _bucket_pos == it._bucket_pos && _it == it._it;
	}
	HashIterator operator++(int) {
		HashIterator ret = *this;
		++(*this);
		return ret;
	}
private:
	size_t _bucket_pos = 0;
	std::list<V>::iterator _it;//这里是iterator ,如果是const_iterator传就构造不了了。应该是这里的问题, 
	std::vector <std::list<V>>* _table;
};

template<class K,class V,class GetK, class hashfunc,class predfunc>
class Hash {
	using self = Hash<K,V, GetK,hashfunc, predfunc>;
	using Iterator = HashIterator<const K, V,V*,V&>;
	using const_Iterator = HashIterator<const K,V,const V*,const V&>;

	size_t hashMap(size_t hashNum, size_t capacity)const{
		if (!capacity)return 0;
		if (!(capacity & (capacity - 1))) {
			return hashNum & (capacity - 1);
		}
		else {
			return hashNum % capacity;
		}
	}
	size_t findNextPowerOfTwo(size_t n) {
		if (n == 0) {
			return 1;
		}
		n--;
		n |= n >> 1;
		n |= n >> 2;
		n |= n >> 4;
		n |= n >> 8;
		n |= n >> 16;
		if constexpr (sizeof(int*) == 8) {
			n |= n >> 32;
		}
		return n + 1;
	}
public:
	Iterator begin() {
		size_t pos = 0;
		while (pos<_buckets&&_table[pos].empty())++pos;
		if (pos == _buckets)return end();
		return { pos,_table[pos].begin(),&_table };
	}
	Iterator end() {
		return { _buckets-1,_table.back().end(),&_table};
	}
	const_Iterator begin()const {
		size_t pos = 0;
		while (pos < _buckets && _table[pos].empty())++pos;
		if (pos == _buckets)return end();
		return const_Iterator(pos,_table[pos].begin(),&_table );
	}
	const_Iterator end()const{
		return const_Iterator(_buckets - 1,_table.back().end(),&_table);
	}
public:
	Hash()  {
		_table.resize(_buckets);
	}
	std::pair<Iterator,bool> insert(const K& key,const V&value) {
		size_t pos = hashMap(_hash(key), _buckets);
		auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
		if (_table[pos].end() != it) {
			return { {pos,it,&_table},false };
		}
		_table[pos].emplace_back(value);
		++_size;
		if (load_factor() > _max_load_factor) {
			reserve(_size + 1); 
			return { find(key),true };
		}
		else {
			return { {pos,--_table[pos].end(),&_table},true };
		}
	}
	std::pair<Iterator, bool> insert(const K& key,V&& value) {
		size_t pos = hashMap(_hash(key), _buckets);
		auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
		if (_table[pos].end() != it) {
			return { {pos,it,&_table},false };
		}
		_table[pos].emplace_back(std::forward<V>(value));
		++_size;
		if (load_factor() > _max_load_factor) {
			reserve(_size + 1);
			return { find(key),true };
		}
		else {
			return { {pos,--_table[pos].end(),&_table},true };
		}
	}
	template<class...Args >
	std::pair<Iterator, bool> emplace(Args&&...args) {
		std::tuple<Args&&...>tp = std::forward_as_tuple(std::forward<Args>(args)...);
		const K& key = std::get<0>(tp);
		size_t pos = hashMap(_hash(key), _buckets);
		auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
		if (_table[pos].end() != it) {
			return { {pos,it,&_table},false };
		}
		if constexpr (sizeof...(Args) == 2) {
			// 场景1:参数是键+值(各1个参数),直接原位构造
			_table[pos].emplace_back(
				std::forward<decltype(std::get<0>(tp))>(std::get<0>(tp)),
				std::forward<decltype(std::get<1>(tp))>(std::get<1>(tp))
			);
		}
		else {
			// 场景2:参数是键+值的多参数(比如emplace(1, 5, 'a')),需分段构造(后续优化)
			// 这里先给出错误提示,或扩展为通用分段构造逻辑
			static_assert(sizeof...(Args) == 2, "仅支持键+值各一个参数的场景,多参数请使用分段构造");
		}
		if (load_factor() > _max_load_factor) {
			reserve(_size + 1);
			return { find(key),true };
		}
		else {
			return { {pos,--_table[pos].end(),&_table},true };
		}
	}
	const_Iterator find(const K& key)const {
		size_t pos = hashMap(_hash(key), _buckets);
		auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
		if (it != _table[pos].end())return { pos,it,&_table };
		else return end();
	}
	Iterator find(const K& key){
		size_t pos = hashMap(_hash(key), _buckets);
		auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
		if (it != _table[pos].end())return { pos,it,&_table };
		else return end();
	}
	size_t count(const K& key)const {
		if (find(key))return 1;
		else return 0;
	}
	bool erase(const K& key) {
		size_t pos = hashMap(_hash(key), _buckets);
		auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return _getk(v) == key; });
		if (it != _table[pos].end()) {
			_table[pos].erase(it);
			--_size;
			return true;
		}
		return false;
	}
	void swap(self& x) {
		if (&x == this)return;
		std::swap(x._size, _size);
		std::swap(x._buckets, _buckets);
		std::swap(x._table, _table);
		std::swap(x._hash, _hash);
		std::swap(_max_load_factor, x._max_load_factor);
		std::swap(x._getk, _getk);
	}
public:
	float max_load_factor()const {
		return _max_load_factor;
	}
	void max_load_factor(float factor) {
		_max_load_factor = factor;
	}
	float load_factor()const {
		return _size / (1.0f * _buckets);
	}
	void reserve(size_t size) {
		size_t reSize = findNextPowerOfTwo((size*1.0)/ _max_load_factor);
		rehash(reSize);
	}
	void rehash(size_t size) {
		size_t reSize = findNextPowerOfTwo(size);
		if (reSize <= _buckets)return;
		self newHash;
		newHash._buckets = reSize;
		newHash._max_load_factor = _max_load_factor;
		newHash._table.resize(reSize);
		for (auto& num : _table) {
			for (auto n : num) {
				newHash.insert(_getk(n), n);
			}
		}
		swap(newHash);
	}
	void clear() {
		_size = 0;
		_buckets = _default_bucket;
		_table.resize(_default_bucket);
		_max_load_factor = _default_factor;
		for (auto& num : _table) {
			num.clear();
		}
	}

public:
	size_t size()const {
		return _size;
	}
	bool empty()const {
		return !_size;
	}
	size_t bucket_count()const {
		return _buckets;
	}
	size_t max_bucket_count()const {
		return _table.size();
	}
	size_t bucket_size(size_t n)const {
		if (n >= _buckets)return -1;
		return _table[n].size();
	}
private:	
	//增加获取k的仿函数
	GetK _getk;
	inline const static size_t _default_bucket = 8;
	inline const static float _default_factor = 1.0;
	float _max_load_factor = _default_factor;
	size_t _size = 0;
	size_t _buckets = _default_bucket;
	std::vector <std::list<V>> _table;
	hashfunc _hash;
};

但是上面的实现是有点小问题的,如果我们构造一个const unordered_map那么底层的Hash就是const的,那么list就会返回const_iterator。但是我们的迭代器不支持用const_iterator构造,因此就有问题:所以我们加一个const的迭代器实现

cpp 复制代码
#pragma once
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<variant>
#include<map>
#include<set>
#include<type_traits>



namespace dgj {
	template<class K>
	struct hashfunc {
		size_t operator()(const K& x)const {
			return x;
		}
	};
	template<>
	struct hashfunc<std::string> {
		size_t operator()(const std::string& str)const {
			size_t pos = 0;
			for (auto ch : str) {
				pos = pos * 131 + ch;
			}
			return pos;
		}
	};

	template<class K>
	struct predfunc {
		bool operator()(const K& x, const K& y) {
			return x == y;
		}
	};
}



namespace dgj {
	template<class K,class V,class Ptr,class Ref>
	class HashIterator {
	using Self = HashIterator<K, V, Ptr, Ref>;
	using ReSelf = Self&;
	using PtrSelf = Self*;
	public:
		HashIterator(const Self& s) 
			:_bucket_pos(s._bucket_pos),
			_it(s._it),
			_table(s._table)
		{
		}
		HashIterator(size_t pos, std::list<V>::iterator it, std::vector <std::list<V>>* table)
			:_bucket_pos(pos),
			_it(it),
			_table(table)
		{
		}

		Ref operator*() {
			return *_it;
		}
		Ptr operator->() {
			return &(*_it);
		}
		ReSelf operator=(Self& x) {
			if (this != &x) {
				_bucket_pos = x._bucket_pos;
				_it = x._it;
				_table = x._table;
			}
			return *this;
		}
		ReSelf operator++() {
			++_it;
			while (_it == (*_table)[_bucket_pos].end()) {
				_it = (*_table)[++_bucket_pos].begin();
				if (_bucket_pos == _table->size() - 1 && _it == _table->back().end())break;
			}
			return *this;

		}
		bool operator ==(const Self& mit)const {
			return _table == mit._table && _bucket_pos == mit._bucket_pos && mit._it == _it;
				

		}
		HashIterator operator++(int) {
			HashIterator ret = *this;
			++(*this);
			return ret;
		}
	private:
		size_t _bucket_pos = 0;
		std::list<V>::iterator _it;//这里是iterator ,如果是const_iterator传就构造不了了。应该是这里的问题, 
		std::vector <std::list<V>>* _table;
	};


	template<class K, class V, class Ptr, class Ref>
	class constHashIterator {
		using Self = constHashIterator<K, V, Ptr, Ref>;
		using ReSelf = Self&;
		using PtrSelf = Self*;
	public:
		constHashIterator(const Self& s)
			:_bucket_pos(s._bucket_pos),
			_it(s._it),
			_table(s._table)
		{
		}
		constHashIterator(size_t pos, std::list<V>::const_iterator it,const std::vector <std::list<V>>* table)
			:_bucket_pos(pos),
			_it(it),
			_table(table)
		{
		}

		Ref operator*() {
			return *_it;
		}
		Ptr operator->() {
			return &(*_it);
		}
		ReSelf operator=(Self& x) {
			if (this != &x) {
				_bucket_pos = x._bucket_pos;
				_it = x._it;
				_table = x._table;
			}
			return *this;
		}
		ReSelf operator++() {
			++_it;
			while (_it == (*_table)[_bucket_pos].end()) {
				_it = (*_table)[++_bucket_pos].begin();
				if (_bucket_pos == _table->size() - 1 && _it == _table->back().end())break;
			}
			return *this;

		}
		bool operator ==(const Self& mit)const {
			return _table == mit._table && _bucket_pos == mit._bucket_pos && mit._it == _it;


		}
		constHashIterator operator++(int) {
			constHashIterator ret = *this;
			++(*this);
			return ret;
		}
	private:
		size_t _bucket_pos = 0;
		std::list<V>::const_iterator _it;//这里是iterator ,如果是const_iterator传就构造不了了。应该是这里的问题, 
		const std::vector <std::list<V>>* _table;
	};

	template<class K,class V,class GetK, class hashfunc,class predfunc>
	class Hash {
		using self = Hash<K,V, GetK,hashfunc, predfunc>;
		using Iterator = HashIterator< K, V,V*,V&>;
		using const_Iterator = constHashIterator< K,V,const V*,const V&>;

		size_t hashMap(size_t hashNum, size_t capacity)const{
			if (!capacity)return 0;
			if (!(capacity & (capacity - 1))) {
				return hashNum & (capacity - 1);
			}
			else {
				return hashNum % capacity;
			}
		}
		size_t findNextPowerOfTwo(size_t n) {
			if (n == 0) {
				return 1;
			}
			n--;
			n |= n >> 1;
			n |= n >> 2;
			n |= n >> 4;
			n |= n >> 8;
			n |= n >> 16;
			if constexpr (sizeof(int*) == 8) {
				n |= n >> 32;
			}
			return n + 1;
		}
	public:
		Iterator begin() {
			size_t pos = 0;
			while (pos<_buckets&&_table[pos].empty())++pos;
			if (pos == _buckets)return end();
			return { pos,_table[pos].begin(),&_table };
		}
		Iterator end() {
			return { _buckets-1,_table.back().end(),&_table};
		}
		const_Iterator begin()const {
			size_t pos = 0;
			while (pos < _buckets && _table[pos].empty())++pos;
			if (pos == _buckets)return end();
			return const_Iterator(pos,_table[pos].begin(),&_table );
		}
		const_Iterator end()const{
			return const_Iterator(_buckets - 1,_table.back().end(),&_table);
		}
	public:
		Hash()  {
			_table.resize(_buckets);
		}
		std::pair<Iterator,bool> insert(const K& key,const V&value) {
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
			if (_table[pos].end() != it) {
				return { {pos,it,&_table},false };
			}
			_table[pos].emplace_back(value);
			++_size;
			if (load_factor() > _max_load_factor) {
				reserve(_size + 1); 
				return { find(key),true };
			}
			else {
				return { {pos,--_table[pos].end(),&_table},true };
			}
		}
		std::pair<Iterator, bool> insert(const K& key,V&& value) {
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
			if (_table[pos].end() != it) {
				return { {pos,it,&_table},false };
			}
			_table[pos].emplace_back(std::forward<V>(value));
			++_size;
			if (load_factor() > _max_load_factor) {
				reserve(_size + 1);
				return { find(key),true };
			}
			else {
				return { {pos,--_table[pos].end(),&_table},true };
			}
		}
		template<class...Args >
		std::pair<Iterator, bool> emplace(Args&&...args) {
			std::tuple<Args&&...>tp = std::forward_as_tuple(std::forward<Args>(args)...);
			const K& key = std::get<0>(tp);
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
			if (_table[pos].end() != it) {
				return { {pos,it,&_table},false };
			}
			if constexpr (sizeof...(Args) == 2) {
				// 场景1:参数是键+值(各1个参数),直接原位构造
				_table[pos].emplace_back(
					std::forward<decltype(std::get<0>(tp))>(std::get<0>(tp)),
					std::forward<decltype(std::get<1>(tp))>(std::get<1>(tp))
				);
			}
			else {
				// 场景2:参数是键+值的多参数(比如emplace(1, 5, 'a')),需分段构造(后续优化)
				// 这里先给出错误提示,或扩展为通用分段构造逻辑
				static_assert(sizeof...(Args) == 2, "仅支持键+值各一个参数的场景,多参数请使用分段构造");
			}
			if (load_factor() > _max_load_factor) {
				reserve(_size + 1);
				return { find(key),true };
			}
			else {
				return { {pos,--_table[pos].end(),&_table},true };
			}
		}
		const_Iterator find(const K& key)const {
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
			if (it != _table[pos].end())return { pos,it,&_table };
			else return end();
		}
		Iterator find(const K& key){
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return  _getk(v) == key; });
			if (it != _table[pos].end())return { pos,it,&_table };
			else return end();
		}
		size_t count(const K& key)const {
			if (find(key))return 1;
			else return 0;
		}
		bool erase(const K& key) {
			size_t pos = hashMap(_hash(key), _buckets);
			auto it = std::find_if(_table[pos].begin(), _table[pos].end(), [&](const V& v) {return _getk(v) == key; });
			if (it != _table[pos].end()) {
				_table[pos].erase(it);
				--_size;
				return true;
			}
			return false;
		}
		void swap(self& x) {
			if (&x == this)return;
			std::swap(x._size, _size);
			std::swap(x._buckets, _buckets);
			std::swap(x._table, _table);
			std::swap(x._hash, _hash);
			std::swap(_max_load_factor, x._max_load_factor);
			std::swap(x._getk, _getk);
		}
	public:
		float max_load_factor()const {
			return _max_load_factor;
		}
		void max_load_factor(float factor) {
			_max_load_factor = factor;
		}
		float load_factor()const {
			return _size / (1.0f * _buckets);
		}
		void reserve(size_t size) {
			size_t reSize = findNextPowerOfTwo((size*1.0)/ _max_load_factor);
			rehash(reSize);
		}
		void rehash(size_t size) {
			size_t reSize = findNextPowerOfTwo(size);
			if (reSize <= _buckets)return;
			self newHash;
			newHash._buckets = reSize;
			newHash._max_load_factor = _max_load_factor;
			newHash._table.resize(reSize);
			for (auto& num : _table) {
				for (auto n : num) {
					newHash.insert(_getk(n), n);
				}
			}
			swap(newHash);
		}
		void clear() {
			_size = 0;
			_buckets = _default_bucket;
			_table.resize(_default_bucket);
			_max_load_factor = _default_factor;
			for (auto& num : _table) {
				num.clear();
			}
		}

	public:
		size_t size()const {
			return _size;
		}
		bool empty()const {
			return !_size;
		}
		size_t bucket_count()const {
			return _buckets;
		}
		size_t max_bucket_count()const {
			return _table.size();
		}
		size_t bucket_size(size_t n)const {
			if (n >= _buckets)return -1;
			return _table[n].size();
		}
	private:	
		//增加获取k的仿函数
		GetK _getk;
		inline const static size_t _default_bucket = 8;
		inline const static float _default_factor = 1.0;
		float _max_load_factor = _default_factor;
		size_t _size = 0;
		size_t _buckets = _default_bucket;
		std::vector <std::list<V>> _table;
		hashfunc _hash;
	};
}

最后加了operator[]的unorderedMap

cpp 复制代码
#pragma once
#include"hash.h"
#include<string>
#include<initializer_list>



namespace dgj {
	template<class K,class T, class HashFunc = hashfunc<K>, class PredFunc = predfunc<K>>
	class unorderedMap {
		using V = std::pair<K, T>;
		using self = unorderedMap<K,T,HashFunc, PredFunc>;
		struct GetK {
			const K& operator()(const V& t)const {
				return t.first;
			}
		};
	public:
		using iterator = HashIterator< K, V,V*,V&>;
		using const_iterator = constHashIterator< K, V,const V*,const V&>;
	public:
		iterator begin() { return _hash.begin(); }
		iterator end() { return _hash.end(); }
		const_iterator begin()const { return _hash.begin(); }
		const_iterator end()const const{ return _hash.end(); }
		unorderedMap(){}
		unorderedMap(const std::initializer_list<V>&il){
			size_t size = il.size();
			reserve(size);
			for (auto& v : il)insert(v);
		}
		bool empty()const { return _hash.empty(); }
		size_t size()const { return _hash.size(); }
		size_t count(const K& k) { return _hash.count(k); }
		iterator find(const K& k) { return _hash.find(k); }
		template<class...Args>
		std::pair<iterator,bool> emplace(Args&&... args) { return _hash.emplace(std::forward<Args>(args)...); }
		std::pair<iterator, bool>  insert(const V&t) { return _hash.insert(t.first, t); }
		std::pair<iterator, bool>  insert(V&&t) { return _hash.insert(t.first, std::forward<V>(t)); }
		void erase(const K& k) { _hash.erase(k); }
		void clear() { _hash.clear(); }
		void swap(self& x) { _hash.swap(x._hash); }
		size_t bucket_count()const { return _hash.bucket_count(); }
		size_t max_bucket_count()const { return _hash.max_bucket_count(); }
		size_t bucket_size(size_t pos)const { return _hash.bucket_size(pos); }
		float load_factor()const { return _hash.load_factor(); }
		void max_load_factor(float f) { return _hash.max_load_factor(f); }
		float max_load_factor()const { return _hash.max_load_factor(); }
		void rehash(size_t size) { return _hash.rehash(size); }
		void reserve(size_t size) { return _hash.reserve(size); }
		T& operator[](const K& x) {
			return emplace(x, T()).first->second;
		}
	private:
		Hash<K, V, GetK, HashFunc, PredFunc>_hash;
	};
}
相关推荐
csbysj20202 小时前
jEasyUI 条件设置行背景颜色
开发语言
JIngJaneIL2 小时前
基于java+ vue交友系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·交友
普通网友2 小时前
Bash语言的图算法
开发语言·后端·golang
hetao17338372 小时前
2025-12-21~22 hetao1733837的刷题笔记
c++·笔记·算法
m0_743125132 小时前
claude --version 报错Claude Code on Windows requires git-bash (https://git-scm.com/downloads/win).
开发语言·git·bash
24级计算机应用技术3班闫卓2 小时前
Bash Shell 基础操作全面指南
开发语言·bash
雨岚霏2 小时前
Bash语言的数据库编程
开发语言·后端·golang
被AI抢饭碗的人2 小时前
linux:线程池
linux·开发语言
lsx2024062 小时前
Kotlin 继承
开发语言