unordered_map 和 unordered_set 的模拟实现

🌻个人主页路飞雪吖~

       🌠专栏:C/C++


目录

一、哈希表开散列的实现

二、解决 KeyOfT 问题

三、iterator 模拟实现

四、const_iterator 模拟实现

五、 Insert()  / Find() / Erase()  的改造

⭐Insert()

⭐Find()

⭐Erase()

六、unordered_map 的 operator[ ] 的实现

八、完整代码 


本篇文章,重点是:unordered_mapunordered_set 模拟实现是如何进行封装的,封装的细节需要注意哪些,注意看仔细哦~

一、哈希表开散列的实现

1、要实现构造、析构(有资源需要清理)、插入(如何扩容)、查找、删除(注意桶里面数据的前后链接关系);

2、要解决存入数据为 字符串 如何取模的问题,这里采用的是模板特化;

想了解更多的细节,可以查看上一章的内容哦~

// HashTable.h

template<class K>
struct HashFunc//当是浮点数、有符号的负数、指针,此时取模都能完美的解决
{
	size_t operator()(const K& key)
	{
		return (size_t)key;//强制转换
	}
};

//模板特化(要有原模版才能特化)
template<>
struct HashFunc<string>//当是字符串时,返回数字能解决,取模的问题
{
	size_t operator()(const string& s)
	{
		size_t hash = 0;
		for (auto e : s)
		{
			hash *= 31;//降低ASCII相加后的重复率
			hash += e;//ASCII码相加
		}
		return hash;
	}
};


namespace hash_bucket//开散列
{
	 template<class K,class V>
	 struct HashNode
	 {
		 pair<K, V> _kv;
		 HashNode<K, V>* _next;

		 HashNode(const pair<K,V>& kv)
			 :_kv(kv)
			 ,_next(nullptr)
		 {}
	 };

	 template<class K,class V, class Hash = HashFunc<K>>
	 class HashTable
	 {
		 typedef HashNode<K, V> Node;
	 public:
		 //构造
		 HashTable()
		 {
			 _tables.resize(10, nullptr);
		 }

		 //要写析构,vector释放的时候,不会释放桶里面(挂在下面的链表)的数据(内置类型),指针不会调用析构函数
		 ~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;
			 }
		 }


		 bool Insert(const pair<K, V>& kv)
		 {
			 Hash hs;
			 size_t hashi = hs(kv.first) % _tables.size();//取模算出hashi对应的位置出来

			 //控制负载因子
			 //负载因子==1 扩容
			 //负载因子越低,空间效率越低,时间效率越高
			 //负载因子越高,空间效率越高,时间效率越低
			 if (_n == _tables.size())//负载因子到1,进行扩容
			 {
				 //直接挪动结点
				 vector<Node*> newtables(_tables.size() * 2, nullptr);
				 for (size_t i = 0; i < _tables.size(); i++)//遍历原来的旧表
				 {
					 Node* cur = _tables[i];
					 while (cur)//遍历桶
					 {
						 //提前保存下一个结点,不然下次找不到
						 Node* next = cur->_next;

						//直接把旧表中的结点,挪到新表重新映射的位置
						 size_t hashi = hs(cur->_kv.first) % newtables.size();//在新表找到对应的位置
						 //头插到新表
						 cur->_next = newtables[hashi];//我先指向桶的第一个
						 newtables[hashi] = cur;//把桶的第一个给我

						 cur = next;
					 }
					 _tables[i] = nullptr;//桶的最后一个指向空
				 }
				 _tables.swap(newtables);//交换表
			 }

			 //头插
			 Node* newnode = new Node(kv);
			 //找到位置,进行头插
			 newnode->_next = _tables[hashi];//(第一个的地址在表里面)表里面指向桶里的第一个
			 _tables[hashi] = newnode;//把桶里面的第一个给newnode(在桶里面头插)
			 ++_n;

			 return true;
		 }

		 Node* Find(const K& key)
		 {
			 Hash hs;
			 size_t hashi = hs(key) % _tables.size();//先算在表里面的位置
			 Node* cur = _tables[hashi];
			 while (cur)
			 {
				 if (cur->_kv.first == key)
				 {
					 return cur;
				 }
				 cur = cur->_next;
			 }
			 return nullptr;
		 }

		 bool Erase(const K& key)
		 {
			 size_t hashi = key % _tables.size();
			 Node* prev = nullptr;
			 Node* cur = _tables[hashi];
			 while (cur)
			 {
				 if (cur->_kv.first == key)
				 {
					 //有这个结点,进行删除,分情况进行讨论
					 if (prev == nullptr)
					 {
						 //没有前一个,直接指向下一个
						 _tables[hashi] = cur->_next;
					 }
					 else
					 {
						 //有前一个,就让前一个的next指向我的后一个
						 prev->_next = cur->_next;
					 }
					 delete cur; 
					 --_n;
					 return true;
				 }
				 prev = cur;
				 cur = cur->_next;
			 }
			 return false;
		 }

	 private:
		 //vector<list<pair<K, V>>> _tables;//指针数组

		 vector<Node*> _tables;//本质是一个指针数组
		 size_t _n = 0;//表中存储的数据个数数据
	 };

二、解决 KeyOfT 问题

我们使用模板来传递类型:

当传入的是 K,T 就为 K;

当传入的是 pair<K,V> ,T 就为键值对。

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

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

KeyOfT 是什么? unordered_map和unordered_set的底层是哈希表,实际就是对哈希表进行封装,我们这里实现的 unordered_map和unordered_set 套用的是同一个哈希表,在实现 Find()Erasr() 、Insert() 函数时,我们比较的是 Key(关键码) ,unordered_set里面存储的是唯一的Key,unordered_map里面存储的是Key和映射值,为了实现统一,我们需要获取 unordered_map里面的Key值,为此我们需要写一个获取Key的类:

// unordered_Set.h

namespace xlf
{
	template<class K, class Hash = HashFunc<K>>
	class UnorderdeSet
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)// 仿函数 为取 pair 的 first
			{
				return key;
			}
		};

	public:

	private:
		hash_bucket::HashTable<K, K, SetKeyOfT, Hash> _ht;
	};
}
// unordered_Map.h

namespace xlf
{
	template<class K, class V, class Hash=HashFunc<K>>
	class UnorderdeMap
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)// 仿函数 取 pair 的 first
			{
				return kv.first;
			}
		};


	private:
		hash_bucket::HashTable<K, pair<K,V>, MapKeyOfT, Hash> _ht;

	};
}

 在实现 Find()Erasr() 、Insert() 函数时,只要是需要获取键值对的key值的位置,都需要对其做出修改:

KeyOfT kot;
Hash hs;
size_t hashi = hs(kot(data.first)) % _tables.size();

三、iterator 模拟实现

1、先在 底层(HashTable)里实现迭代器:

      • 注意要前置声明,防止使用HashTable时,找不到;

      • 迭代器里面要存 节点 和 哈希表对象的指针;

      • Ptr 为 指针,Ref 为 &

      • 注意operator++ 的实现细节。

// HashTable.h

//前置声明(迭代器需要使用HashTable,但是哈希表在下面定义,编译器编译的时候只会往上面取查找)
template<class K, class T, class KeyOfT, class Hash>
class HashTable;

template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>
struct HTIterator
{
	typedef HashNode<T> Node;
	typedef HTIterator<K, T, Ptr, Ref, KeyOfT, Hash> Self;

	Node* _node;
	//const的作用: 防止const迭代器传参时,权限放大,从而导致编译不通过,普通迭代器不受影响(权限可以缩小)
	const HashTable<K, T, KeyOfT, Hash>* _pht;//把哈希表对象的指针传过来

	//const的作用: 防止const迭代器传参时,权限放大,从而导致编译不通过,普通迭代器不受影响(权限可以缩小)
	HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht)
		:_node(node)
		,_pht(pht)
	{}

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

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

	bool operator!=(const Self& s)
	{
		return _node != s._node;
	}

	Self& operator++()
	{
		if (_node->_next)//桶不为空,一直访问桶里面的结点
		{
			//当前桶还有结点
			_node = _node->_next;
		}
		else//桶为空
		{
			//当前桶走完了,找下一个不为空的桶
			KeyOfT kot;
			Hash hs;
			size_t hashi = hs(kot(_node->_data)) %  _pht->_tables.size();
			++hashi;
			while (hashi < _pht->_tables.size())
			{
				if (_pht->_tables[hashi])//这个桶不为空,就一直往下一个数据走
				{
					break;
				}
				++hashi;
			}

			if (hashi == _pht->_tables.size())//每个桶都走完了
			{
				_node = nullptr;//end()
			}
			else
			{
				//桶没走完
				_node = _pht->_tables[hashi];//取桶里面的数据
			}
		}
		return *this;
	}
};

 2、在哈希表里实现具体的 Begin() End()

// HashTable.h

typedef HTIterator<K, T, T*, T&, KeyOfT, Hash> Iterator;

Iterator Begin()
{
	if (_n == 0)
		return End();

	for (size_t i = 0; i < _tables.size(); i++)
	{
		Node* cur = _tables[i];
		if (cur)
		{
			return Iterator(cur, this);
		}
	}
	return End();
}

Iterator End()
{
	return Iterator(nullptr, this);
}

 3、先把哈希表的迭代器引入到unordered_setunordered_map 里面,接着分别在 unordered_set unordered_map 里面对哈希表里面的迭代器进行封装(“套壳”)。

// unordered_Set.h

typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator;


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

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

// unordered_Map.h

typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::Iterator iterator;

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

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

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

四、const_iterator 模拟实现

1、在哈希表里面加上 const_Iterator;

typedef HTIterator<K, T, const T*, const T&, KeyOfT, Hash> ConstIterator;


ConstIterator Begin() const
{
	if (_n == 0)
		return End();

	for (size_t i = 0; i < _tables.size(); i++)
	{
		Node* cur = _tables[i];
		if (cur)
		{
			return ConstIterator(cur, this);
		}
	}
	return End();
}

ConstIterator End() const
{
	return ConstIterator(nullptr, this);
}

2、分别在unordered_setunordered_map 里面,对哈希表里面的const迭代器进行封装(“套壳)

// unordered_Set.h

typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::ConstIterator const_iterator;

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

const_iterator end() const
{
	return _ht.End();
}
// unordered_Map.h

typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::ConstIterator const_iterator;

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

const_iterator end() const
{
	return _ht.End();
}

五、 Insert()  / Find() / Erase()  的改造

Insert()

修改返回值:

 bool --改为--> pair<Iterator,bool>;

 false --改为--> make_pair(it,false);

 true --改为--> make_pair(Iterator(newnode,this),true);

// HashTable.h

pair<Iterator,bool> Insert(const T& data)
{
	//...
		return make_pair(it,false);
	
//...
	return make_pair(Iterator(newnode,this),true);
}

 分别在unordered_Set 和 unordered_Map 里面实现 insert() :("套壳")

// unordered_Set.h

pair<iterator, bool> insert(const K& key)
{
	return _ht.Insert(key);
}
// unordered_Map.h

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

Find()

分别在unordered_Set 和 unordered_Map 里面实现 find() :("套壳")

// unordered_Set.h

iterator find(const K& key)
{
	return _ht.Find(key);
}
// unordered_Map.h

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

Erase()

分别在unordered_Set unordered_Map 里面实现 erase() :("套壳")

// unordered_Set.h

iterator erase(const K& key)
{
	return _ht.Erase(key);
}
// unordered_Map.h

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

六、unordered_map 的 operator[ ] 的实现

V& operator[](const K& key)
{
	//如果这个值已经有了,它就会返回key对应所在的节点的迭代器
	//没有就会先插入一个pair,pair的key为新插入的迭代器
	pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
	return ret.first->second;
}

八、完整代码 

// HashTable.h


#pragma once
#include<iostream>
#include<vector>
#include<string>
using namespace std;

template<class K>
struct HashFunc//当是浮点数、有符号的负数、指针,此时取模都能完美的解决
{
	size_t operator()(const K& key)
	{
		return (size_t)key;//强制转换
	}
};

//模板特化(要有原模版才能特化)
template<>
struct HashFunc<string>//当是字符串时,返回数字能解决,取模的问题
{
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (auto e : key)
		{
			hash *= 31;//降低ASCII相加后的重复率
			hash += e;//ASCII码相加
		}
		return hash;
	}
};


namespace hash_bucket
{
	template<class T>
	struct HashNode
	{
		T _data;// const K  ,此时,data是const不能修改
		HashNode<T>* _next;

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

	//前置声明(迭代器需要使用HashTable,但是哈希表在下面定义,编译器编译的时候只会往上面取查找)
	template<class K, class T, class KeyOfT, class Hash>
	class HashTable;

	template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>
	struct HTIterator
	{
		typedef HashNode<T> Node;
		typedef HTIterator<K, T, Ptr, Ref, KeyOfT, Hash> Self;

		Node* _node;
		//const的作用: 防止const迭代器传参时,权限放大,从而导致编译不通过,普通迭代器不受影响(权限可以缩小)
		const HashTable<K, T, KeyOfT, Hash>* _pht;//把哈希表对象的指针传过来

		//const的作用: 防止const迭代器传参时,权限放大,从而导致编译不通过,普通迭代器不受影响(权限可以缩小)
		HTIterator(Node* node, const HashTable<K, T, KeyOfT, Hash>* pht)
			:_node(node)
			,_pht(pht)
		{}

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

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

		bool operator!=(const Self& s)
		{
			return _node != s._node;
		}

		Self& operator++()
		{
			if (_node->_next)//桶不为空,一直访问桶里面的结点
			{
				//当前桶还有结点
				_node = _node->_next;
			}
			else//桶为空
			{
				//当前桶走完了,找下一个不为空的桶
				KeyOfT kot;
				Hash hs;
				size_t hashi = hs(kot(_node->_data)) %  _pht->_tables.size();
				++hashi;
				while (hashi < _pht->_tables.size())
				{
					if (_pht->_tables[hashi])//这个桶不为空,就一直往下一个数据走
					{
						break;
					}
					++hashi;
				}

				if (hashi == _pht->_tables.size())//每个桶都走完了
				{
					_node = nullptr;//end()
				}
				else
				{
					//桶没走完
					_node = _pht->_tables[hashi];//取桶里面的数据
				}
			}
			return *this;
		}
	};

	//  1、实现哈希表
	//  2、封装unordered_map和unordered_set  解决KeyOfT
	//  3、iterator
	//  4、const_iterator
	//  5、修改Key的问题
	//  6、operator[]

	template<class K, class T, class KeyOfT, class Hash>
	class HashTable
	{
		//模板参数的友元声明
		template<class K, class T, class Ptr, class Ref, class KeyOfT, class Hash>
		friend struct HTIterator;

		typedef HashNode<T> Node;
	public: 
		typedef HTIterator<K, T, T*, T&, KeyOfT, Hash> Iterator;

		typedef HTIterator<K, T, const T*, const T&, KeyOfT, Hash> ConstIterator;

		Iterator Begin()
		{
			if (_n == 0)
				return End();

			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				if (cur)
				{
					return Iterator(cur, this);
				}
			}
			return End();
		}

		Iterator End()
		{
			return Iterator(nullptr, this);
		}

		ConstIterator Begin() const
		{
			if (_n == 0)
				return End();

			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				if (cur)
				{
					return ConstIterator(cur, this);
				}
			}
			return End();
		}

		ConstIterator End() const
		{
			return ConstIterator(nullptr, this);
		}

		//构造
		HashTable()
		{
			_tables.resize(10, nullptr);
		}

		//要写析构,vector释放的时候,不会释放桶里面(挂在下面的链表)的数据(内置类型),指针不会调用析构函数
		~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)
		{
			KeyOfT kot;
			Iterator it = Find(kot(data));
			//不允许重复
			if (it != End())
			{
				return make_pair(it,false);
			}

			Hash hs;
			size_t hashi = hs(kot(data)) % _tables.size();//取模算出hashi对应的位置出来

			//控制负载因子
			//负载因子==1 扩容
			//负载因子越低,空间效率越低,时间效率越高
			//负载因子越高,空间效率越高,时间效率越低
			if (_n == _tables.size())//负载因子到1,进行扩容
			{
				//新开结点
				/*HashTable<K, V> newHT;
				newHT._tables.resize(_tables.size() * 2);
				for (size_t i = 0; i < _tables.size(); i++)//遍历原来的旧表
				{
					Node* cur = _tables[i];
					while (cur)//遍历桶
					{
						newHT.Insert(cur->_kv);//把所以旧表的数据,插入到新表里面
						cur = cur->_next;
					}
				}
				_tables.swap(newHT._tables);//新表和旧表进行交换*/

				//直接挪动结点
				vector<Node*> newtables(_tables.size() * 2, nullptr);
				for (size_t i = 0; i < _tables.size(); i++)//遍历原来的旧表
				{
					Node* cur = _tables[i];
					while (cur)//遍历桶
					{
						//提前保存下一个结点,不然下次找不到
						Node* next = cur->_next;

						//直接把旧表中的结点,挪到新表重新映射的位置
						size_t hashi = hs(kot(cur->_data)) % newtables.size();//在新表找到对应的位置
						//头插到新表
						cur->_next = newtables[hashi];//我先指向桶的第一个
						newtables[hashi] = cur;//把桶的第一个给我

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

			//头插
			Node* newnode = new Node(data);
			//找到位置,进行头插
			newnode->_next = _tables[hashi];//(第一个的地址在表里面)表里面指向桶里的第一个
			_tables[hashi] = newnode;//把桶里面的第一个给newnode(在桶里面头插)
			++_n;

			return make_pair(Iterator(newnode,this),true);
		}

		//不允许冗余
		Iterator Find(const K& key)
		{
			KeyOfT kot;
			Hash hs;
			size_t hashi = hs(key) % _tables.size();//先算在表里面的位置
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					return Iterator(cur,this);
				}
				cur = cur->_next;
			}
			return End();
		}

		bool Erase(const K& key)
		{
			KeyOfT kot;
			Hash hs;

			size_t hashi = hs(key) % _tables.size();
			Node* prev = nullptr;
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					//有这个结点,进行删除,分情况进行讨论
					if (prev == nullptr)
					{
						//没有前一个,直接指向下一个
						_tables[hashi] = cur->_next;
					}
					else
					{
						//有前一个,就让前一个的next指向我的后一个
						prev->_next = cur->_next;
					}
					delete cur;
					--_n;
					return true;
				}
				prev = cur;
				cur = cur->_next;
			}
			return false;
		}

	private:
		//vector<list<pair<K, V>>> _tables;//指针数组

		vector<Node*> _tables;//本质是一个指针数组
		size_t _n = 0;//表中存储的数据个数数据
	};

}
// unordered_Set.h

#pragma once
#include"HashTable.h"

namespace xlf
{
	template<class K, class Hash = HashFunc<K>>
	class Unordered_Set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)// 仿函数 取 pair 的 first
			{
				return key;
			}
		};

	public:
		//const防止key被修改
		typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::ConstIterator 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 K& key)
		{
			return _ht.Insert(key);
		}

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

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

	private:
		hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
	};

	void Print(const Unordered_Set<int>& s)
	{
		Unordered_Set<int>::const_iterator it = s.begin();
		while (it != s.end())
		{
			//*it += 1;//const迭代器不可以修改
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	struct Date
	{
		int _year;
		int _month;
		int _day;

		bool operator==(const Date& d) const
		{
			return _year == d._year
				&& _month == d._month
				&& _day == d._day;
		}
	};

	struct HashDate
	{
		size_t operator()(const Date& key)
		{
			//减少重复(冲突)
			//1月12日
			//12月1日
			return ((key._year * 31 + key._month) * 31 + key._day);
		}
	};

	void test_set()
	{
		Unordered_Set<int> s;
		int a[] = { 4,6,1,3,5,15,7,16,14,4,4,5 };
		for (auto e : a)
		{
			s.insert(e);
		}

		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;

		Unordered_Set<int>::iterator it = s.begin();
		while (it != s.end())
		{
			//*it += 1;//建议不修改key,会导致后面遍历的时候出现问题
			cout << *it << " ";
			++it;
		}
		cout << endl;

		Unordered_Set<Date, HashDate> us;
		us.insert({ 2024,10,11 });
		us.insert({ 2024,10,12 });

		Print(s);
	}

	
}
// unordered_Map.h

#pragma once
#include"HashTable.h"

namespace xlf
{
	template<class K, class V, class Hash = HashFunc<K>>
	class Unordeer_Map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)// 仿函数 取 pair 的 first
			{
				return kv.first;
			}
		};

	public:
		//const防止key被修改
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::ConstIterator 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<K, V>& kv)
		{
			return _ht.Insert(kv);
		}

		V& operator[](const K& key)
		{
			//如果这个值已经有了,它就会返回key对应所在的节点的迭代器
			//没有就会先插入一个pair,pair的key为新插入的迭代器
			pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
			return ret.first->second;
		}

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

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

	private:
		hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
	};

	void test_map()
	{
		Unordeer_Map<string, string> dict;
		dict.insert({ "sort","排序" });
		dict.insert({ "left","左边" });
		dict.insert({ "right","右边" });

		dict["left"] = "左边,剩余";//修改
		dict["insert"] = "插入";//插入+修改
		dict["string"];//纯插入


		Unordeer_Map<string, string>::iterator it = dict.begin();
		while (it != dict.end())
		{
			//不能修改first,可以修改second
			//it->first += 'x';
			it->second += 'x';

			cout << it->first << ":" << it->second << endl;
			++it;
		}
		cout << endl;
	}
}

如若对你有帮助,记得点赞、收藏、关注哦!

若有误,望各位,在评论区留言或者私信我 指点迷津!!!谢谢^ ^ ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值