【C++】unordered_map、unordered_set 模拟实现

概念

unordered_set 是含有 Key 类型唯一对象集合的关联容器。搜索、插入和移除拥有平均常数时间复杂度。在内部,元素并不以任何特别顺序排序,而是组织进桶中。元素被放进哪个桶完全依赖其值的哈希。这允许对单独元素的快速访问,因为哈希一旦确定,就准确指代元素被放入的桶。不可修改容器元素(即使通过非 const 迭代器),因为修改可能更改元素的哈希,并破坏容器。

unordered_map 是关联容器,含有带唯一键的 “键-值” pair 。搜索、插入和元素移除拥有平均常数时间复杂度。元素在内部不以任何特定顺序排序,而是组织进桶中。元素放进哪个桶完全依赖于其键( Key) 的哈希。这允许对单独元素的快速访问,因为一旦计算哈希,则它准确指代元素所放进的桶。

读上面的两段话会显得非常抽象,但是,如果对模拟实现 Map、Set 有一定了解(不了解可以看一下这篇文章 Map、Set模拟实现 ),那么就能很快明白,只不过是 原本用红黑树作为底层数据结构来实现 Map、Set ,现在使用哈希(拉链法)作为底层数据结构来实现 unordered_map、unordered_set 。既然是使用的哈希,那么存储的数据就无法像红黑树一样具有严格的顺序,但是,换来的确是查找效率的极大提高,提高为 O(1) 的查找效率。

框架

如下图,哈希桶本质上是一个 vector ,容器里面存放的是 HashNode 这个节点的指针,节点是一个结构体,结构体里面存储着下一个 HashNode 结构体的指针当前节点的数据

哈希桶的实现自然不必多说,不了解的话可以查看这篇文章:C++ 哈希。这里是使用拉链法解决哈希冲突。
在这里插入图片描述

如下,必然要定义一个 HashNode 结构体,HashFunc 是为了根据 Key 来计算出数据的哈希值,以便得知数据存放在哪一个桶里面,至于 正反向迭代器自然不必多说,必有的配置,最后就是 哈希桶了,其成员变量一个是 _tables ,另一个是用来表示 _tables 中的有效数据个数。


#pragma once
#include<iostream>
#include<vector>

using namespace std;

namespace HashBucket
{
	template<class T>
	struct HashNode
	{
		HashNode<T>* _next;
		T _data;

		HashNode(const T& data)
			:_next(nullptr)
			, _data(data)
		{}
	};


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

	// 模板的特化,如果有 string 类型的数据,优先使用特化的模板
	template<>
	struct HashFunc<string>
	{
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (auto& a : s)
			{
				hash += a;
				hash *= 31;
			}
			return hash;
		}
	};

	// 前置声明,不需要默认参数
	template<class K, class T, class KeyOfT, class Hash>
	class HashTable;


	template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash=HashFunc<K>>
	struct Iterator
	{
	public:
		typedef HashNode<T> Node;
		typedef Iterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
		typedef HashTable<K, T, KeyOfT, Hash> HT;
	public:
		Iterator(Node* node = nullptr, HT* tables= nullptr)
			:_node(node)
			,_ht(tables)
		{}

		Iterator(const Iterator<K,T,T&,T*,KeyOfT,Hash>& it)
			:_node(it._node)
			,_ht(it._ht)
		{}

		Node* _node;
		HT* _ht;
	};


	template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash=HashFunc<K>>
	struct ReverseIterator
	{
		
		typedef HashNode<T> Node;
		typedef ReverseIterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
		typedef HashTable<K, T, KeyOfT, Hash> HT;

		ReverseIterator(Node* node, HT* ht)
		{
			it._node = node;
			it._ht = ht;
		}

		ReverseIterator(const Iterator<K, T,Ref,Ptr,KeyOfT,Hash> rit)
		{
			it._node = rit._node;
			it._ht = rit._ht;
		}

		ReverseIterator(const ReverseIterator<K, T, T&, T*, KeyOfT, Hash>& rit)
		{
			it._node = rit.it._node;
			it._ht = rit.it._ht;
		}


		Iterator<K, T, Ref, Ptr, KeyOfT, Hash> it;
	};

	template<class K, class T, class KeyOfT,class Hash = HashFunc<K>>
	class HashTable
	{
	public:

		typedef HashNode<T> Node;

		typedef Iterator<K, T, T&, T*, KeyOfT, Hash> iterator;
		typedef ReverseIterator<K, T, T&, T*, KeyOfT, Hash> reverse_iterator;

		// 模板类友元,声明不需要默认参数
		template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
		friend struct Iterator;

	public:
		//	成员方法

	private:
		vector<HashNode<T>*> _tables;
		size_t n = 0; // vector 存储有效数据个数
	};

}

对于迭代器、HashTable 的模板参数中, KeyOfT 的作用,和模拟实现 Map、Set 一样,就是为了取得数据的 Key 。因为 unordered_map 存储的是 pair<K,V> ,unordered_set 存储的是 K,为了使 HashTable 可以同时支持它们两个容器,所以有了 KeyOfT,该参数的传参是在 unordered_map 和 unordered_set 里面实现的。

如下,在 unordered_map 里面实现了 KeyOfMap,然后将仿函数传入 HashTable 的对应参数,这样在 HashTable 中,用 KeyOfT 实例化出的 kot 对象,实际上就是 struct KeyOfMap 的对象,再使用 kot 调用重载的 () 就可以拿到 pair<K,V> 中的 K 。
unordered_set 同理,不多赘述。

#include"HashTable.h"

namespace simulate_unorderedmap
{
	template<class K, class V,class Hash=HashBucket::HashFunc<K>>
	class unordered_map
	{
	public:

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

	public:
    // 成员函数

	private:
		HashBucket::HashTable<K, pair<const K, V>, KeyOfMap,Hash> _map;
	};

}

实现

正反迭代器

这里可以使用包装器的设计模式,实现正向迭代器,然后反向迭代器实际上就是对正向迭代器的封装,反向迭代器的++,就是正向迭代器的–。

如下, Iterator 中有两个成员变量,一个是 HashNode 节点的指针,另一个是 HashTable 的指针。需要 _ht 这个成员变量的原因,其实是进行 ++ 、-- 所需要的。

对于成员函数的介绍主要就在 ++ 、-- 这两个。如下图, 我们可以理解为,vector 容器里面装的是一个个桶,桶是链表的结构。进行一次 ++ ,那么迭代器自然是指向链表中下一个节点,此时分为两种情况,下一个节点存在(如下图左边),下一个节点不存在,即当前节点已经是当前桶的最后一个节点(如下图右边)。 对于前者,自然很容易,但是,对于后者,就需要找到下一个有数据的桶,然后将 _node 指针指向桶内第一个节点,具体步骤如下。

  • 1、得到 key。 kot(_node->_data)
  • 2、通过 hash 函数得到 hash 值。 hash(kot(_node->_data))
  • 3、得到桶号(一般都为 hash 值对桶数求模)。size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();
  • 4、找到下一个有数据的桶。

要进行上面的操作,必须要有当前的 HashTable,但是用一整个 HashTable 当作成员变量,消耗太大,所以用指针。
在这里插入图片描述

operator- - () 也是类似的实现,只不过 - - 要先经过前三步得到桶号,然后判断当前节点的前面有没有节点,可以根据桶的第一个节点是不是当前节点进行判断,不难理解。

同时,无论是 ++ 还是 - - 都要注意边界条件,最后一个哈希桶的最后一个数据,进行 ++ 只能是 nullptr, 同样,第一个哈希桶的第一个数据,进行 - - 也只能是 nullptr 。

template<class K, class T, class KeyOfT, class Hash>
	class HashTable;


	template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash=HashFunc<K>>
	struct Iterator
	{
	public:
		typedef HashNode<T> Node;
		typedef Iterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
		typedef HashTable<K, T, KeyOfT, Hash> HT;
	public:
		Iterator(Node* node = nullptr, HT* tables= nullptr)
			:_node(node)
			,_ht(tables)
		{}

		Iterator(const Iterator<K,T,T&,T*,KeyOfT,Hash>& it)
			:_node(it._node)
			,_ht(it._ht)
		{}

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

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

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

		self& operator++()
		{
			if (_node->_next)
			{
				_node = _node->_next;
				return *this;
			}

			// 找到下一个有数据的桶
			KeyOfT kot;
			Hash 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;
				}
				else
				{
					++hashi;
				}
			}

			if (hashi >= _ht->_tables.size())
				_node = nullptr;

			return *this;
		}

		self& operator--()
		{
			// 找到当前桶
			KeyOfT kot;
			Hash hash;
			int hashi = hash(kot(_node->_data)) % _ht->_tables.size();
			
			// 桶的第一个就是当前节点构成的迭代器,往前面的桶找
			if (_ht->_tables[hashi] == _node)
			{
				--hashi;
				while (hashi >= 0)
				{
					if (_ht->_tables[hashi] == nullptr)
					{
						--hashi;
					}
					else
					{
						// 找到上一个有数据的桶的最后一个数据
						Node* cur = _ht->_tables[hashi];
						while (cur->_next)
							cur = cur->_next;
						_node = cur;
						break;
					}
				}

				if (hashi < 0)
					_node = nullptr;
			}
			else // 桶的第一个不是当前节点构成的迭代器,在该桶里面找
			{
				Node* cur = _ht->_tables[hashi];
				while (cur->_next != _node)
				{
					cur = cur->_next;
				}
				_node = cur;
			}

			return *this;
		}

		Node* _node;
		HT* _ht;
	};

至于反向迭代器,那就是对正向迭代器的封装。

template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash=HashFunc<K>>
	struct ReverseIterator
	{
		
		typedef HashNode<T> Node;
		typedef ReverseIterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
		typedef HashTable<K, T, KeyOfT, Hash> HT;

		ReverseIterator(Node* node, HT* ht)
		{
			it._node = node;
			it._ht = ht;
		}

		ReverseIterator(const Iterator<K, T,Ref,Ptr,KeyOfT,Hash> rit)
		{
			it._node = rit._node;
			it._ht = rit._ht;
		}

		ReverseIterator(const ReverseIterator<K, T, T&, T*, KeyOfT, Hash>& rit)
		{
			it._node = rit.it._node;
			it._ht = rit.it._ht;
		}

		self operator++()
		{
			return --it;
		}

		self& operator--()
		{
			return ++it;
		}

		Ref operator*()
		{
			return it._node->_data;
		}

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

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

		Iterator<K, T, Ref, Ptr, KeyOfT, Hash> it;
	};

Find()、Insert() 、Erase()

如下是 unordered_map、unordered_set 里面的 Find() 、Erase() 、Insert() 方法,其实就是对 HashTable 的封装。知道了 HashTable 里面的 Find() 、insert() 、Erase() 实现原理即可,并不难,都是和 ++ 类似的思路。

#include"HashTable.h"

namespace simulate_unorderedmap
{
	template<class K, class V,class Hash=HashBucket::HashFunc<K>>
	class unordered_map
	{
	public:

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

	public:
		typedef typename HashBucket::HashNode<pair<const K, V>> Node;

		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::iterator iterator;
		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::const_iterator const_iterator;
		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::reverse_iterator reverse_iterator;
		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::const_reverse_iterator const_reverse_iterator;

		iterator begin()
		{
			return _map.begin();
		}

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

		pair<iterator,bool> insert(const pair<const K, V>& kv)
		{
			return _map.insert(kv);
		}

		iterator Find(const K& key)
		{
			Node* cur = _map.Find(key);
			return iterator(cur, &_map);
		}

		bool Erase(const K& key)
		{
			return _map.Erase(key);
		}

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


	private:
		HashBucket::HashTable<K, pair<const K, V>, KeyOfMap,Hash> _map;
	};

}

unordered_map 的 operator[ ]

unordered_map 的 [ ] 是兼具插入查找功能的。unordered_map 里面存储的是 pair<K,V> ,假设有一个 unordered_map< int,int >对象 m,执行 m[10]=1000; —— 如果存储的 pair<K,V> 里面,有 K 类型的数据是 10,那么就将这个键值对的 V 修改成 100;没有则插入 make_pair(10,100);

要完成上面描述的功能,就必须要让 [ ] 的返回值是 V& (V的引用),这样才可以修改 V 类型的数据。 可以通过迭代器来实现!!

如下是 unordered_map 里面实现 operator[ ] 的代码,_map 是 HashTable 实例化出来的对象,其 Insert() 返回值是 pair<iterator,bool> , 很明显,返回值包含两个信息:

  • 1.某个节点构成的迭代器。如果插入成功,那么返回插入节点封装成的迭代器。如果插入失败(已经有了 K 类型对应的数据),那么就相当于查找功能,返回找到的节点封装成的迭代器
  • 2.是否插入成功,插入成功返回 true,否则false。
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _map.insert(make_pair(key, V()));
			return ret.first->second;
		}

源代码

HashTable.h

#pragma once
#include<iostream>
#include<vector>

using namespace std;

namespace HashBucket
{
	template<class T>
	struct HashNode
	{
		HashNode<T>* _next;
		T _data;

		HashNode(const T& data)
			:_next(nullptr)
			, _data(data)
		{}
	};


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

	// 模板的特化,如果有 string 类型的数据,优先使用特化的模板
	template<>
	struct HashFunc<string>
	{
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (auto& a : s)
			{
				hash += a;
				hash *= 31;
			}
			return hash;
		}
	};

	// 前置声明,不需要默认参数
	template<class K, class T, class KeyOfT, class Hash>
	class HashTable;


	template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash=HashFunc<K>>
	struct Iterator
	{
	public:
		typedef HashNode<T> Node;
		typedef Iterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
		typedef HashTable<K, T, KeyOfT, Hash> HT;
	public:
		Iterator(Node* node = nullptr, HT* tables= nullptr)
			:_node(node)
			,_ht(tables)
		{}

		Iterator(const Iterator<K,T,T&,T*,KeyOfT,Hash>& it)
			:_node(it._node)
			,_ht(it._ht)
		{}

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

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

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

		self& operator++()
		{
			if (_node->_next)
			{
				_node = _node->_next;
				return *this;
			}

			// 找到下一个有数据的桶
			KeyOfT kot;
			Hash 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;
				}
				else
				{
					++hashi;
				}
			}

			if (hashi >= _ht->_tables.size())
				_node = nullptr;

			return *this;
		}

		self& operator--()
		{
			// 找到当前桶
			KeyOfT kot;
			Hash hash;
			int hashi = hash(kot(_node->_data)) % _ht->_tables.size();
			
			// 桶的第一个就是当前节点构成的迭代器,往前面的桶找
			if (_ht->_tables[hashi] == _node)
			{
				--hashi;
				while (hashi >= 0)
				{
					if (_ht->_tables[hashi] == nullptr)
					{
						--hashi;
					}
					else
					{
						// 找到上一个有数据的桶的最后一个数据
						Node* cur = _ht->_tables[hashi];
						while (cur->_next)
							cur = cur->_next;
						_node = cur;
						break;
					}
				}

				if (hashi < 0)
					_node = nullptr;
			}
			else // 桶的第一个不是当前节点构成的迭代器,在该桶里面找
			{
				Node* cur = _ht->_tables[hashi];
				while (cur->_next != _node)
				{
					cur = cur->_next;
				}
				_node = cur;
			}

			return *this;
		}

		Node* _node;
		HT* _ht;
	};


	template<class K,class T,class Ref,class Ptr,class KeyOfT,class Hash=HashFunc<K>>
	struct ReverseIterator
	{
		
		typedef HashNode<T> Node;
		typedef ReverseIterator<K, T, Ref, Ptr, KeyOfT, Hash> self;
		typedef HashTable<K, T, KeyOfT, Hash> HT;

		ReverseIterator(Node* node, HT* ht)
		{
			it._node = node;
			it._ht = ht;
		}

		ReverseIterator(const Iterator<K, T,Ref,Ptr,KeyOfT,Hash> rit)
		{
			it._node = rit._node;
			it._ht = rit._ht;
		}

		ReverseIterator(const ReverseIterator<K, T, T&, T*, KeyOfT, Hash>& rit)
		{
			it._node = rit.it._node;
			it._ht = rit.it._ht;
		}

		self operator++()
		{
			return --it;
		}

		self& operator--()
		{
			return ++it;
		}

		Ref operator*()
		{
			return it._node->_data;
		}

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

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

		Iterator<K, T, Ref, Ptr, KeyOfT, Hash> it;
	};

	template<class K, class T, class KeyOfT,class Hash = HashFunc<K>>
	class HashTable
	{
	public:

		typedef HashNode<T> Node;

		typedef Iterator<K, T, T&, T*, KeyOfT, Hash> iterator;
		typedef Iterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;
		typedef ReverseIterator<K, T, T&, T*, KeyOfT, Hash> reverse_iterator;
		typedef ReverseIterator<K, T, const T&, const T*, KeyOfT, Hash> const_reverse_iterator;

		// 模板类友元,声明不需要默认参数
		template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
		friend struct Iterator;

	public:

		iterator begin()
		{
			Node* cur = nullptr;
			for (int i = 0; i < _tables.size(); i++)
			{
				cur = _tables[i];
				if (cur)
					break;
			}

			return iterator(cur, this);
		}

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

		const_iterator begin()const
		{
			Node* cur = nullptr;
			for (int i = 0; i < _tables.size(); i++)
			{
				cur = _tables[i];
				if (cur)
					break;
			}

			return const_iterator(cur, this);
		}

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


		reverse_iterator rbegin()
		{
			int hashi = _tables.size() - 1;
			while (_tables[hashi] == nullptr && hashi>=0)
			{
				hashi--;
			}
			if (hashi < 0)
				return reverse_iterator(nullptr, this);

			// 最后一个
			Node* cur = _tables[hashi];
			while (cur->_next)
				cur = cur->_next;
			return reverse_iterator(cur, this);
		}

		reverse_iterator rend()
		{
			return reverse_iterator(nullptr, this);
		}


		const_reverse_iterator rbegin()const
		{
			int hashi = _tables.size() - 1;
			while (_tables[hashi] == nullptr && hashi >= 0)
			{
				hashi--;
			}
			if (hashi < 0)
				return const_reverse_iterator(nullptr, this);

			// 最后一个
			Node* cur = _tables[hashi];
			while (cur->_next)
				cur = cur->_next;
			return const_reverse_iterator(cur, this);
		}

		const_reverse_iterator rend()const
		{
			return const_reverse_iterator(nullptr, this);
		}

		bool Erase(const K& key)
		{
			KeyOfT kot;
			Hash hash;
			size_t hashi = hash(key) % _tables.size();
			Node* cur = _tables[hashi];
			Node* prev = nullptr;
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						_tables[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}

			return false;
		}

		Node* Find(const K& key)
		{
			if (_tables.size() == 0)
				return nullptr;

			Hash hash;
			KeyOfT kot;
			size_t hashi = hash(key) % _tables.size();

			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
					return cur;
				cur = cur->_next;
			}
			return nullptr;
		}


		size_t GetNextPrime(size_t prime)
		{
			// SGI
			static const int __stl_num_primes = 28;
			static const unsigned long __stl_prime_list[__stl_num_primes] =
			{
				53, 97, 193, 389, 769,
				1543, 3079, 6151, 12289, 24593,
				49157, 98317, 196613, 393241, 786433,
				1572869, 3145739, 6291469, 12582917, 25165843,
				50331653, 100663319, 201326611, 402653189, 805306457,
				1610612741, 3221225473, 4294967291
			};

			size_t i = 0;
			for (; i < __stl_num_primes; ++i)
			{
				if (__stl_prime_list[i] > prime)
					return __stl_prime_list[i];
			}

			return __stl_prime_list[i];
		}

		pair<iterator,bool> insert(const T& data)
		{
			KeyOfT kot;
			Node* findnode = Find(kot(data));
			if (findnode)
				return make_pair(iterator(findnode, this), false);

			Hash hash;

			if (_tables.size() == n)
			{
				//size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;

				size_t newsize = GetNextPrime(_tables.size());

				vector<Node*> newtables(newsize, nullptr);
				for (auto& cur : _tables)
				{
					while (cur) // 链表节点全部插入newht
					{
						Node* next = cur->_next;
						size_t newhashi = hash(kot(cur->_data)) % newsize;

						cur->_next = newtables[newhashi];
						newtables[newhashi] = cur;

						cur = next;
					}
				}

				_tables.swap(newtables);
			}

			size_t hashi = hash(kot(data)) % _tables.size();
			Node* tmp = new Node(data);
			tmp->_next = _tables[hashi];
			_tables[hashi] = tmp;

			++n;
			return make_pair(iterator(tmp,this),true);

		}


		size_t MaxBucketSize()
		{
			int size = _tables.size();
			size_t max = 0;
			for (int i = 0; i < size; i++)
			{
				size_t tmp = 0;
				Node* cur = _tables[i];
				while (cur)
				{
					tmp++;
					cur = cur->_next;
				}

				if (tmp > max)
					max = tmp;
			}

			return max;
		}

	private:
		vector<HashNode<T>*> _tables;
		size_t n = 0; // vector 存储有效数据个数
	};

}

unordered_map.h

#include"HashTable.h"



namespace simulate_unorderedmap
{
	template<class K, class V,class Hash=HashBucket::HashFunc<K>>
	class unordered_map
	{
	public:

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

	public:
		typedef typename HashBucket::HashNode<pair<const K, V>> Node;

		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::iterator iterator;
		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::const_iterator const_iterator;
		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::reverse_iterator reverse_iterator;
		typedef typename HashBucket::HashTable<K, pair<const K, V>, KeyOfMap, Hash>::const_reverse_iterator const_reverse_iterator;

		iterator begin()
		{
			return _map.begin();
		}

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

		pair<iterator,bool> insert(const pair<const K, V>& kv)
		{
			return _map.insert(kv);
		}

		iterator Find(const K& key)
		{
			Node* cur = _map.Find(key);
			return iterator(cur, &_map);
		}

		bool Erase(const K& key)
		{
			return _map.Erase(key);
		}

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


	private:
		HashBucket::HashTable<K, pair<const K, V>, KeyOfMap,Hash> _map;
	};

}

unordered_set.h

#include"HashTable.h"

namespace simulate_unorderedset
{

	template<class K, class Hash = HashBucket::HashFunc<K>>
	class unordered_set
	{
	public:
		typedef typename HashBucket::HashNode<K> Node;
		struct KeyOfSet
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};

	public:

		typedef typename HashBucket::HashTable<K, K, KeyOfSet, Hash>::const_iterator iterator;
		typedef typename HashBucket::HashTable<K, K, KeyOfSet, Hash>::const_iterator const_iterator;
		typedef typename HashBucket::HashTable<K, K, KeyOfSet, Hash>::const_reverse_iterator reverse_iterator;
		typedef typename HashBucket::HashTable<K, K, KeyOfSet, Hash>::const_reverse_iterator const_reverse_iterator;

		pair<iterator,bool> insert(const K& key)
		{
			return _set.insert(key);
		}

		bool Erase(const K& key)
		{
			return _set.Erase(key);
		}

		iterator Find(const K& key)
		{
			Node* cur=_set.Find(key);
			return iterator(cur, &_set);
		}

		iterator begin()
		{
			return _set.begin();
		}

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

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

		const_iterator end()const
		{
			return _set.end();
		}

		reverse_iterator rbegin()
		{
			return _set.rbegin();
		}

		reverse_iterator rend()
		{
			return _set.rend();
		}


	private:
		HashBucket::HashTable<K, K, KeyOfSet,Hash> _set;
	};

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力努力再努力.xx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值