unordered_map&&unordered_set封装

unordered_map&&unordered_set介绍

看名字是和map\set类似的迭代器,和map\set的区别如下:

  1. map底层是红黑树封装;unordered_map底层是哈希桶
  2. map支持双向迭代器;unordered_map只支持++
  3. map是有序的序列;unordered_map是无序的序列
  4. unordered_map的查找效率比map快

接口方面和map类似,参照map/set的使用即可。

unordered_set

哈希桶的封装部分

哈希桶的代码:哈希桶代码部分参考这里
为了更好适合封装map,在哈希桶里面修改内容如下:

  1. 添加了迭代器,提供了*,->,++,!=等功能。
  2. 哈希桶增加了begin和end函数
  3. 哈希桶insert的返回值修改(为了在map里实现[])
  4. 添加了const迭代器

具体实现出现的问题,在代码的注释中,有所体现:

namespace HashBucket
{
	//T表示数据类型
	template<class T>
	struct Elem
	{
		Elem(const T& data)
			:_data(data)
			, _next(nullptr)
		{}


		T _data;
		Elem<T>* _next;
	};

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

	//特化版本
	template<>
	struct Hash<string>
	{
		//BKDR哈希*31
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (auto e : s)
			{
				hash += e;
				hash *= 31;
			}
			return hash;
		}
	};


	//迭代器实现
	//迭代器用到了哈希表,需要前置声明一下(声明不需要写默认传参)
	template<class K, class T, class KeyOFT, class HashFunc>
	class HashTables;


	// K索引, T数据类型, Ref:T的引用 , Ptr:T的指针, KeyOFT:获取T的索引
	template<class K, class T, class Ref, class Ptr, class KeyOFT, class HashFunc = Hash<K>>
	struct _HashIterator
	{
		typedef Elem<T> Node;
		typedef HashTables<K, T, KeyOFT, HashFunc> HT;
		typedef _HashIterator<K, T, Ref, Ptr, KeyOFT, HashFunc> Self;
		typedef _HashIterator<K, T, T&, T*, KeyOFT, HashFunc> Iterator;


		//const迭代器,不在这定义,在哈希表定义
		//typedef _HashIterator<K, const T, const T&, const T*, KeyOFT, HashFunc> const_Iterator;
		/*typedef _HashIterator<K, T, const T&, const T*, KeyOFT, HashFunc> const_Iterator;*/
		
		Node* _node;
		const HT* _ht;   //迭代器还需要哈希表,因为要换桶,没有表无法完成换桶



		//构造  begin要用,所以要public
	public:
		_HashIterator(Node* node, const HT* ht)
			:_node(node)
			,_ht(ht)
		{}

		//如果是普通迭代器,就是拷贝构造
		//如果是const,就是构造函数
		//_HashIterator(const Iterator& it)
		//	:_node(it._node)
		//	, _ht(it._ht)
		//{}

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

		//没有形参
		//Ref operator->(const Node* node)
		Ref operator*()
		{
			return _node->_data;
		}


		// !=号的迭代器注意一下
		bool operator!=(const Self& s)
		{
			return _node != s._node;
		}


		Self& operator++()
		{
			//next不为空,下一个结点就是next
			if (_node->_next)
			{
				_node = _node->_next;
				return *this;
			}

			KeyOFT kot;
			HashFunc 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;
				}
				hashi++;
			}
			if (hashi == _ht->_tables.size())   //没找到非空的结点.说明是最后一个
			{
				_node = nullptr;
			}

			return *this;

		}
	};





	//K表示查找值时的索引, T表示数据类型,KeyOFT获取T的索引K,HashFunc计算Hash的函数
	template<class K, class T, class KeyOFT, class HashFunc = Hash<K>>
	class HashTables
	{
		//迭代器要访问私有的_tables,得是友元
		template<class K, class T, class Ref, class Ptr, class KeyOFT, class HashFunc>
		friend struct _HashIterator;


		typedef Elem<T> Node;    
		typedef T Data;

		//迭代器的typedef,
		//unordered_map的
	public:
		typedef _HashIterator<K, T, T&, T*, KeyOFT, HashFunc> iterator;
		//const 迭代器
		typedef _HashIterator<K, T, const T&, const T*, KeyOFT, HashFunc> const_iterator;

	public:
		//此版本不太好
		//Iterator begin()
		//{
		//	Node* cur = nullptr;

		//	for (auto e : _tables)
		//	{
		//		if (e)
		//		{
		//			return Iterator(e, this);
		//		}
		//	}
		//}


		iterator begin()
		{
			Node* cur = nullptr;

			for (auto e : _tables)
			{
				if (e)
				{
					cur = e;
					break;
				}
			}
			return iterator(cur, this);
		}

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


		const_iterator begin() const
		{
			Node* cur = nullptr;

			for (auto e : _tables)
			{
				if (e)
				{
					cur = e;
					break;
				}
			}
			return const_iterator(cur, this);
		}

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


		pair<iterator, bool> insert(const Data& data)
		{
			//负载因子过大就扩容
			CheckCapacity();
			HashFunc hash;
			KeyOFT kot;

			iterator it = find(kot(data));
			//if (it._node)    //查到了,直接返回,不能访问迭代器的成员变量
			if(it!=end())
			{
				/*return make_pair(iterator(cur,this), false);*/
				return make_pair(it, false);
			}


			//散列地址
			size_t hashi = hash(kot(data)) % _tables.size();

			//直接插入头插
			Node* newNode = new Node(data);
			newNode->_next = _tables[hashi];
			_tables[hashi] = newNode;
			n++;
			return make_pair(iterator(newNode, this), true);

		}

		iterator find(const K& key)
		{
			HashFunc hash;
			KeyOFT kot;
			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 erase(const K& key)
		{
			HashFunc hash;
			KeyOFT kot;
			size_t hashi = hash(key) % _tables.size();
			Node* cur = _tables[hashi];
			Node* prev = nullptr;
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					if (!prev)   //prev为空,说明是在表上
					{
						_tables[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					return true;
				}
				prev = cur;
				cur = cur->_next;
			}
			return false;

		}
	private:
		//扩容有问题,不应该插入一个就扩容,插入一个就扩容!!!!!!!!!!!!
		void CheckCapacity()
		{
			KeyOFT kot;
			HashFunc hash;
			//表为空或者负载因子大于0.7了就扩容
			//if (!_tables.size() || ((n * 10) / (_tables.size() * 10) > 7))
			/*if (!_tables.size() || ((n * 10) / _tables.size() > 7))*/
			if (n == _tables.size())
			{
				size_t newCapacity = (_tables.size() == 0 ? 10 : _tables.size() * 2);
				HashTables* newHashTable = new HashTables;
				newHashTable->_tables.resize(newCapacity);

				//将旧表的数据重新映射到新表
				//遍历旧表
				for (auto& e : _tables)
				{
					if (e)  //不空,就有数据
					{
						Node* cur = e;
						Node* next;   //下一个指针
						while (cur)
						{
							size_t hashi = hash(kot(cur->_data)) % newCapacity;
							next = cur->_next;  //暂存下一个
							cur->_next = newHashTable->_tables[hashi];
							newHashTable->_tables[hashi] = cur;     //头插
							//newHashTable->n++;
							cur = next;

						}
					}
				}

				//swap(*newHashTable, *this);
				_tables.swap(newHashTable->_tables);

			}
		}

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

unordered_map的封装

  1. 迭代器类中只实现基本的操作不实现begin/end,哈希桶表提供begin/end,哈希桶里面通过typedef实现const迭代器的规则;
  2. map外面暴露了三个模板参数,可以自定义hash函数
  3. 支持[]取数据
  4. 注意成员变量定义方法
namespace xty
{
	template<class K>
	struct Hash
	{
		size_t operator()(const K& key)
		{
			return key;
		}
	};

	//特化版本
	template<>
	struct Hash<string>
	{
		//BKDR哈希*31
		size_t operator()(const string& s)
		{
			size_t hash = 0;
			for (auto e : s)
			{
				hash += e;
				hash *= 31;
			}
			return hash;
		}
	};

	template<class K, class V,class HashFunc=Hash<K>>
	class unordered_map
	{
		struct MyKeyOFT;   //声明一下
		//迭代器重命名
	public:
		typedef typename HashBucket::HashTables<K, pair<const K, V>, MyKeyOFT, HashFunc>::iterator iterator;
		typedef typename HashBucket::HashTables<K, pair<const K, V>, MyKeyOFT, HashFunc>::const_iterator const_iterator;
	private:
		//只有自己知道自己的数据类型是什么样
		struct MyKeyOFT
		{
			const K& operator()(const pair<K, V>& data)
			{
				return data.first;
			}
		};

	public:

		iterator begin()
		{
			return _hash.begin();
		}
		iterator end()
		{
			return _hash.end();
		}



		//要让map支持[],需要将insert的返回函数修改一下
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = Insert(make_pair(key, V()));

			return ret.first->second;
		}


		//插入
		pair<iterator, bool> Insert(const pair<K, V>& data)
		{
			return _hash.insert(data);
		}

		//删除
		bool Erase(const K& key)
		{
			return _hash.erase(key);
		}

		pair<K, V>* Find(const K& key)
		{
			return _hash.find(key);
		}


	private:
		HashBucket::HashTables<K, pair<const K, V>, MyKeyOFT, HashFunc> _hash;
		//HashBucket::HashTables<K, V, MyKeyOFT> _hash;   注意要传pair ,不然insert报错
	};





	void unordered_map_test()
	{
		int a[]= { 11, 22, 33, 44, 55, 66, 77, 88, 99, 111, 444, 555,1111 };

		unordered_map<int, int> map;

		for (auto e : a)
		{
			map.Insert(make_pair(e, e));
		}


	}
}

添加一段测试代码检验第三个模板参数的正确性:

class Date
	{
		friend struct HashDate;
	public:
		Date(int year = 1900, int month = 1, int day = 1)
			: _year(year)
			, _month(month)
			, _day(day)
		{}

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

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

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

		friend ostream& operator<<(ostream& _cout, const Date& d);
	private:
		int _year;
		int _month;
		int _day;
	};

	ostream& operator<<(ostream& _cout, const Date& d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}

	struct HashDate
	{
		size_t operator()(const Date& d)
		{
			size_t hash = 0;
			hash += d._year;
			hash *= 31;

			hash += d._month;
			hash *= 31;

			hash += d._day;
			hash *= 31;

			return hash;
		}
	};

	// 一个类型要做unordered_map/unordered_set的key,要满足支持转换成取模的整形 和 ==比较
	// 一个类型要做map/set的key,要满足支持<比较
	/*if (cur->key < key)
	{}
	else if (key < cur->key)
	{}
	else
	{}*/

	void test_unordered_map4()
	{
		Date d1(2023, 3, 13);
		Date d2(2023, 3, 13);
		Date d3(2023, 3, 12);
		Date d4(2023, 3, 11);
		Date d5(2023, 3, 12);
		Date d6(2023, 3, 13);

		Date a[] = { d1, d2, d3, d4, d5, d6 };

		unordered_map<Date, int, HashDate> countMap;
		for (auto e : a)
		{
			countMap[e]++;
		}

		for (auto& kv : countMap)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
	}

unordered_set封装

  1. 注意成员变量的参数不加const K
  2. typename
	template<class K, class HashFunc=Hash<K>>
	class unordered_set
	{
		struct SetOFT;
	public:
		//外面要使用迭代器,所以放public
		typedef typename HashBucket::HashTables<K, K, SetOFT, HashFunc>::const_iterator iterator;
		typedef typename HashBucket::HashTables<K, K, SetOFT, HashFunc>::const_iterator const_iterator;
	public:
		struct SetOFT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};

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

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


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

		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);
		}

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


	private:
		//不加pair<K,K>
		/*HashBucket::HashTables<K, pair<K, K>, SetOFT, HashFunc>*/

		/*HashBucket::HashTables<K, const K, SetOFT, HashFunc> _ht;*/
		HashBucket::HashTables<K, K, SetOFT, HashFunc> _ht;
	};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值