unordered_map和unordered_set的模拟实现

C++哈希表(散列表)

哈希表的定义

哈希表是一种根据关键字(键)直接访问存储位置的数据结构。它通过哈希函数将键映射到哈希表中的索引位置。哈希函数接受一个键作为输入,并输出对应的索引。这样,我们可以在常数时间内(O(1))访问和查找元素。

哈希冲突

哈希表的哈希函数并不是一一映射的,不同键可能映射到相同的索引位置,这就是哈希冲突。哈希冲突是不可避免的,但我们需要寻找合适的方法来解决冲突。处理哈希冲突的方法有链地址法、开放地址法等

链地址法

链地址法通过在哈希表中的每个索引位置维护一个链表,每个链表存储哈希值相同的元素。当发生哈希冲突时,我们将新元素添加到对应索引位置的链表中。链地址法简单易用,能够有效解决冲突,但需要额外的链表空间。

开放地址法

开放地址法通过在哈希表的冲突位置继续探查其他索引位置,直到找到空闲的位置来存储元素。这种方法节省了额外链表空间,但需要设计好的探查序列,否则可能导致性能下降。

unordered_map的模拟实现
namespace bit
{
	// 为了实现简单,在哈希桶的迭代器类中需要用到hashBucket本身,
	template<class K, class V, class KeyOfValue, class HF>
	class HashBucket;


	// 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作
	template <class K, class V, class KeyOfValue, class HF>
	struct HBIterator
	{
		typedef HashBucket<K, V, KeyOfValue, HF> HashBucket;
		typedef HashBucketNode<V>* PNode;
		typedef HBIterator<K, V, KeyOfValue, HF> Self;


		HBIterator(PNode pNode = nullptr, HashBucket* pHt = nullptr)
		{
			_pNode = pNode;
			_pHt = pHt;
		}
		Self& operator++()
		{
			// 当前迭代器所指节点后还有节点时直接取其下一个节点
			if (_pNode->_pNext)
				_pNode = _pNode->_pNext;
			else
			{
				// 找下一个不空的桶,返回该桶中第一个节点
				size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data)) + 1;
				for (; bucketNo < _pHt->BucketCount(); ++bucketNo)
				{
					if (_pNode = _pHt->_ht[bucketNo])
						break;
				}
			}


			return *this;
		}
		Self operator++(int)
		{
			Self temp = *this;
			// 当前迭代器所指节点后还有节点时直接取其下一个节点
			if (_pNode->_pNext)
				_pNode = _pNode->_pNext;
			else
			{
				// 找下一个不空的桶,返回该桶中第一个节点
				size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data)) + 1;
				for (; bucketNo < _pHt->BucketCount(); ++bucketNo)
				{
					if (_pNode = _pHt->_ht[bucketNo])
						break;
				}
			}
			return temp;
		}
		V& operator*()
		{
			return _pNode->_data;
		}
		V* operator->()
		{
			return &_pNode->_data;
		}
		bool operator==(const Self& it) const
		{
			return _pNode == it._pNode;
		}
		bool operator!=(const Self& it) const
		{
			return _pNode != it._pNode;
		}
		PNode _pNode;             // 当前迭代器关联的节点
		HashBucket* _pHt;         // 哈希桶--主要是为了找下一个空桶时候方便
	};


	// unordered_map中存储的是pair<K, V>的键值对,K为key的类型,V为value的类型,HF哈希函数类型
	// unordered_map在实现时,只需将hashbucket中的接口重新封装即可
	template<class K, class V, class HF = DefHashF<K>>
	class unordered_map
	{
		typedef HashBucket<K, pair<K, V>, KeyOfValue, HF> HT;
		// 通过key获取value的操作
		struct KeyOfValue
		{
			const K& operator()(const pair<K, V>& data)
			{
				return data.first;
			}
		};
	public:
		typename typedef HT::Iterator iterator;
	public:
		unordered_map() : _ht()
		{}
		
		iterator begin() { return _ht.begin(); }
		iterator end() { return _ht.end(); }
		
		// capacity
		size_t size()const { return _ht.size(); }
		bool empty()const { return _ht.empty(); }
		///
		// Acess
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _ht.InsertUnique(pair<K, V>(key, V()));
			return ret.fisrt->second;
		}
		const V& operator[](const K& key)const
		{
			pair<iterator, bool> ret = _ht.InsertUnique(pair<K, V>(key, V()));
			return ret.fisrt->second;
		}
		//
		// lookup
		iterator find(const K& key) { return _ht.Find(key); }
		size_t count(const K& key) { return _ht.Count(key); }
		/
		// modify
		pair<iterator, bool> insert(const pair<K, V>& valye)
		{
			return _ht.Insert(valye);
		}


		iterator erase(iterator position)
		{
			return _ht.Erase(position);
		}
		
		// bucket
		size_t bucket_count() { return _ht.BucketCount(); }
		size_t bucket_size(const K& key) { return _ht.BucketSize(key); }
	private:
		HT _ht;
	};
}
unordered_set的模拟实现
namespace bit
{
	// 为了实现简单,在哈希桶的迭代器类中需要用到hashBucket本身,
	template<class K, class V, class KeyOfValue, class HF>
	class HashBucket;


	// 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作
	template <class K, class V, class KeyOfValue, class HF>
	struct HBIterator
	{
		typedef HashBucket<K, V, KeyOfValue, HF> HashBucket;
		typedef HashBucketNode<V>* PNode;
		typedef HBIterator<K, V, KeyOfValue, HF> Self;


		HBIterator(PNode pNode = nullptr, HashBucket* pHt = nullptr)
		{
			_pNode = pNode;
			_pHt = pHt;
		}
		Self& operator++()
		{
			// 当前迭代器所指节点后还有节点时直接取其下一个节点
			if (_pNode->_pNext)
				_pNode = _pNode->_pNext;
			else
			{
				// 找下一个不空的桶,返回该桶中第一个节点
				size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data)) + 1;
				for (; bucketNo < _pHt->BucketCount(); ++bucketNo)
				{
					if (_pNode = _pHt->_ht[bucketNo])
						break;
				}
			}


			return *this;
		}
		Self operator++(int)
		{
			Self temp = *this;
			// 当前迭代器所指节点后还有节点时直接取其下一个节点
			if (_pNode->_pNext)
				_pNode = _pNode->_pNext;
			else
			{
				// 找下一个不空的桶,返回该桶中第一个节点
				size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data)) + 1;
				for (; bucketNo < _pHt->BucketCount(); ++bucketNo)
				{
					if (_pNode = _pHt->_ht[bucketNo])
						break;
				}
			}
			return temp;
		}
		V& operator*()
		{
			return _pNode->_data;
		}
		V* operator->()
		{
			return &_pNode->_data;
		}
		bool operator==(const Self& it) const
		{
			return _pNode == it._pNode;
		}
		bool operator!=(const Self& it) const
		{
			return _pNode != it._pNode;
		}
		PNode _pNode;             // 当前迭代器关联的节点
		HashBucket* _pHt;         // 哈希桶--主要是为了找下一个空桶时候方便
	};


	// unordered_set中存储的是K类型,HF哈希函数类型
	// unordered_set在实现时,只需将hashbucket中的接口重新封装即可
	template<class K, class HF = DefHashF<K>>
	class unordered_set
	{
		typedef HashBucket<K, K, KeyOfValue, HF> HT;
		// 通过key获取value的操作
		struct KeyOfValue
		{
			const K& operator()(const K& data)
			{
				return data;
			}
		};
	public:
		typename typedef HT::Iterator iterator;
	public:
		unordered_set() : _ht()
		{}
		
		iterator begin() { return _ht.begin(); }
		iterator end() { return _ht.end(); }
		
		// capacity
		size_t size()const { return _ht.size(); }
		bool empty()const { return _ht.empty(); }
		///
		// lookup
		iterator find(const K& key) { return _ht.Find(key); }
		size_t count(const K& key) { return _ht.Count(key); }
		/
		// modify
		pair<iterator, bool> insert(const K& valye)
		{
			return _ht.Insert(valye);
		}


		iterator erase(iterator position)
		{
			return _ht.Erase(position);
		}
		
		// bucket
		size_t bucket_count() { return _ht.BucketCount(); }
		size_t bucket_size(const K& key) { return _ht.BucketSize(key); }
	private:
		HT _ht;
	};
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值