30.用哈希表封装实现myunordered_map和myunordered_set

思路和用红黑树封装map和set类似

27.用红黑树封装实现mymap和myset-优快云博客

哈希表的结构如下所示

template<class K, class T,class KOfT, class Hash = HashFun<K>>
class HashBucket
{
private:
	vector<Node*> _bucket;
	size_t _n = 0; // 表中存储的数据个数
};

K为键值,T为节点里存的数据的类型,KOfT是为了让unordered_map取出key值的仿函数,Hash是将K值转化成无符号整形的仿函数,默认支持能强转成整形,对string做了特化。

哈希表的迭代器

迭代器的结构如下:

template<class T, class KOfT,class Ref,class Ptr, class Hash>
class HashBucket_iterator
{
private:
	Node* _node;
	const vector<Node*>* _bucket;
};

T为节点里存的数据的类型,KOfT是为了让unordered_map取出key值的仿函数,Ref为T的引用或者const引用,Ptr为T的指针或者const指针,为了一份模板可以同时实例化出iterator和const_iterator。Hash是将K值转化成无符号整形的仿函数,需要靠HashBucket传参。

成员变量:

_node为当前结点的指针

_bucket为哈希表的指针,为了跨单个桶时,能找到下一个桶。

迭代器的operator++实现:

思路:若当前节点的next不为空,当前单链表没有走完,_node = _node->_next,返回;

若当前节点的next为空,就要根据当前节点的key转整形计算出哈希值,从当前节点的下一个开始遍历vector,直到头结点指针不为空或者vector遍历完了,头节点指针不为空,让_node等于头指针,返回;若vector遍历完了,就让_node指向空(即end())。

Self& operator++()
{
	assert(_node);
	//下一个为空,已经是单链表的尾了
	if (_node->_next == nullptr)
	{
		KOfT kot;
		size_t hashi = kot(_node->_data) % (*_bucket).size();
		++hashi;
		//找下一个不为空的头
		while (hashi < (*_bucket).size())
		{
			if ((*_bucket)[hashi] != nullptr)
			{
				_node = (*_bucket)[hashi];
				return *this;
			}
			++hashi;
		}
		//vector被遍历完了
		_node = nullptr;
		return *this;
	}
	else
	{
		_node = _node->_next;
	}
	return *this;
}

unordered_map的operator[]实现:

V& operator[](const K& key)
{
	pair<iterator, bool> ret = insert({ key,V() });
	//iterator->返回data* -> second,省略了一个->
	//返回V&
	return ret.first->second;
}

以下是完整代码:

HashTable.h

#pragma once
using namespace std;
#include<vector>
#include<string>
#include<algorithm>
#include<assert.h>

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

inline unsigned long __stl_next_prime(unsigned long n)
{
	const unsigned long* first = __stl_prime_list;
	const unsigned long* last = __stl_prime_list + __stl_num_primes;
	const unsigned long* pos = lower_bound(first, last, n);
	return pos == last ? *(last - 1) : *pos;
}

template<class K>
struct HashFun
{
	size_t operator()(const K& key)
	{
		return static_cast<size_t>(key);
	}
};
template<>
struct HashFun<string>
{
	size_t operator()(const string& key)
	{
		size_t ret = 0;
		for (auto e : key)
		{
			ret += e;
			ret *= 131;
		}
		return ret;
	}
};

template<class T>
struct ListNode
{
	ListNode(const T& data)
		:_data(data)
		, _next(nullptr)
	{}
	T _data;
	ListNode<T>* _next;
};

template<class T, class KOfT,class Ref,class Ptr, class Hash>
class HashBucket_iterator
{
private:
	typedef typename ListNode<T> Node;
	typedef typename HashBucket_iterator<T, KOfT, Ref, Ptr, Hash> Self;
public:
	HashBucket_iterator(Node* node,const vector<Node*>* bucket)
		:_node(node)
		,_bucket(bucket)
	{}
	Ref operator*()
	{
		return _node->_data;
	}
	Ptr operator->()
	{
		return &_node->_data;
	}
	bool operator!=(const Self& hbit)
	{
		return _node != hbit._node;
	}
	bool operator==(const Self& hbit)
	{
		return _node == hbit._node;
	}

	Self& operator++()
	{
		assert(_node);
		//下一个为空,已经是单链表的尾了
		if (_node->_next == nullptr)
		{
			KOfT kot;
			size_t hashi = kot(_node->_data) % (*_bucket).size();
			++hashi;
			//找下一个不为空的头
			while (hashi < (*_bucket).size())
			{
				if ((*_bucket)[hashi] != nullptr)
				{
					_node = (*_bucket)[hashi];
					return *this;
				}
				++hashi;
			}
			//vector被遍历完了
			_node = nullptr;
			return *this;
		}
		else
		{
			_node = _node->_next;
		}
		return *this;
	}
private:
	Node* _node;
	const vector<Node*>* _bucket;
};

template<class K, class T,class KOfT, class Hash = HashFun<K>>
class HashBucket
{
private:
	typedef typename ListNode<T> Node;
public:
	typedef typename HashBucket_iterator<T, KOfT, T&, T*, Hash> Iterator;
	typedef typename HashBucket_iterator<T, KOfT, const T&, const T*, Hash> ConstIterator;
public:
	HashBucket(const size_t sz = 11)
	{
		_bucket.resize(sz);
	}

	~HashBucket()
	{
		for (size_t i = 0; i < _bucket.size(); ++i)
		{
			if (_bucket[i] != nullptr)
			{
				Node* cur = _bucket[i];
				Node* next = cur->_next;
				while (cur)
				{
					delete cur;
					cur = next;
					if (cur)
						next = cur->_next;
				}
			}
		}
	}

	Iterator Begin()
	{
		Node* begin = nullptr;
		size_t curi = 0;
		while (curi<_bucket.size())
		{
			if (_bucket[curi])
			{
				begin = _bucket[curi];
				break;
			}
			++curi;
		}
		return Iterator(begin,&_bucket);
	}

	Iterator End()
	{
		return Iterator(nullptr, &_bucket);
	}

	pair<Iterator,bool> Insert(const T& data)
	{
		KOfT kot;
		Iterator it = Find(kot(data));
		//找到了,插入失败
		if (it != End())
			return { it,false };
		//负载因子等于1时,扩容
		if (_n == _bucket.size())
		{
			//思路:将原哈希桶的节点拿下来,插入到新的桶
			vector<Node*> newbucket;
			newbucket.resize(__stl_next_prime(_bucket.size()) + 1);
			size_t newsz = newbucket.size();
			Hash hash;
			//按原桶的vector下标遍历
			for (size_t i = 0; i < _bucket.size(); ++i)
			{
				if (_bucket[i] != nullptr)
				{
					Node* cur = _bucket[i];
					Node* next = cur->_next;
					//cur即为当前遍历的节点
					// 将其 头插 到新的哈希桶中
					while (cur)
					{
						size_t hashi = hash(kot(cur->_data)) % newsz;
						//头插,cur head,cur成为新的头
						cur->_next = newbucket[hashi];
						newbucket[hashi] = cur;
						//迭代
						cur = next;
						if (cur)
							next = cur->_next;
					}
				}
				_bucket[i] = nullptr;
			}
			_bucket.swap(newbucket);
		}
		Hash hash;
		size_t hashi = hash(kot(data)) % _bucket.size();
		Node* newnode = new Node(data);
		//头插,newnode head,newnode成为新的头
		newnode->_next = _bucket[hashi];
		_bucket[hashi] = newnode;
		++_n;
		return { { newnode,&_bucket }, false };
	}

	Iterator Find(const K& key)
	{
		Hash hash;
		KOfT kot;
		size_t hashi = hash(key) % _bucket.size();
		Node* cur = _bucket[hashi];
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				return { cur,&_bucket };
			}
			cur = cur->_next;
		}
		return { nullptr,&_bucket };
	}

	bool Erase(const K& key)
	{
		Hash hash;
		KOfT kot;
		size_t hashi = hash(key) % _bucket.size();
		Node* cur = _bucket[hashi];
		//cur为头结点的指针
		if (cur == nullptr)
			return false;
		//头删,_bucket[hashi](cur) curNext
		if (kot(cur->_data) == key)
		{
			_bucket[hashi] = cur->_next;
			delete cur;
			--_n;
			return true;
		}
		//中间删除
		else
		{
			Node* prev = nullptr;
			//prev cur curNext
			while (cur && kot(cur->_data) != key)
			{
				prev = cur;
				cur = cur->_next;
			}
			if (cur == nullptr)
			{
				return false;
			}
			else
			{
				prev->_next = cur->_next;
				delete cur;
				--_n;
				return true;
			}
		}
	}
private:
	vector<Node*> _bucket;
	size_t _n = 0; // 表中存储的数据个数
};

MyUnorderedMap.h

#pragma once
#include "HashTable.h"

namespace quiteSix
{
	template<class K,class V>
	class unordered_map
	{
	private:
		struct unordered_map_KeyOfT
		{
			const K& operator()(const pair<const K, V>& data) const
			{
				return data.first;
			}
		};
	private:
		typedef typename HashBucket<K, pair<const K, V>, unordered_map_KeyOfT> hashbucket;
		typedef typename hashbucket::Iterator iterator;
		typedef typename hashbucket::ConstIterator const_iterator;
	public:
		iterator begin()
		{
			return _hb.Begin();
		}
		iterator end()
		{
			return _hb.End();
		}

		pair<iterator, bool> insert(const pair<const K, V>& data)
		{
			return _hb.Insert(data);
		}
		iterator find(const K& key)
		{
			return _hb.Find(key);
		}
		bool erase(const K& key)
		{
			return _hb.Erase(key);
		}
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = insert({ key,V() });
			//iterator->返回data* -> second,省略了一个->
			//返回V&
			return ret.first->second;
		}
	private:
		hashbucket _hb;
	};
}

MyUnorderedSet.h

#pragma once
#include "HashTable.h"

namespace quiteSix
{
	template<class K>
	class unordered_set
	{
	private:
		struct unordered_set_KeyOfT
		{
			const K& operator()(const K& data) const
			{
				return data;
			}
		};
	private:
		typedef typename HashBucket<K, const K, unordered_set_KeyOfT> hashbucket;
		typedef typename hashbucket::Iterator iterator;
		typedef typename hashbucket::ConstIterator const_iterator;
	public:
		iterator begin()
		{
			return _hb.Begin();
		}
		iterator end()
		{
			return _hb.End();
		}
		pair<iterator, bool> insert(const K& data)
		{
			return _hb.Insert(data);
		}
		iterator find(const K& key)
		{
			return _hb.Find(key);
		}
		bool erase(const K& key)
		{
			return _hb.Erase(key);
		}
	private:
		hashbucket _hb;
	};
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

挺6的还

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

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

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

打赏作者

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

抵扣说明:

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

余额充值