unordered_set和unordered_map模拟实现

目录

1 哈希表实现

1.1 字符串处理

1.2 节点

1.3 迭代器

1.4 表

2 unordered_map

3 unordered_set


1 哈希表实现

        采用开散列哈希表,映射方法为除留余数法。

1.1 字符串处理

使用仿函数对字符串类型的值转换为可以取余的整数。

	template<class K>
	struct Hash
	{
		size_t operator()(const K& key)
		{
			return key;
		}
	};
	template<>
	struct Hash<std::string>
	{
		size_t operator()(const std::string& s)
		{
			size_t res = 0;
			for (auto c : s)
			{
				res *= 31;
				res += c;
			}
			return res;
		}
	};

1.2 节点

哈希桶中为链表,设置为一般的链表节点即可。

	template<class T>
	struct HashNode
	{
		HashNode(T data)
			:_data(data)
			, next(nullptr)
		{}
		T _data;
		HashNode* next;
	};

1.3 迭代器

        由于迭代器++中需要整个哈希表才能寻找到下一个迭代器位置,迭代器中不仅存了节点指针还有整个哈希表的指针。

        整个迭代器实现的难点就是operator++,整体大逻辑是当前节点的下一个位置不为空,下一个位置就是下一个节点。否则就要在哈希表中从当前数组下标找到下一个数组下标位置中不为空的位置,并且该位置的第一个节点就是下一个位置的节点。

	template<class K, class V, class KeyofT, class HashFunc = Hash<K>>
	class HashTable;

	template<class K, class V, class Ref, class Ptr, class KeyofT
,class HashFunc = Hash<K>>
	struct __HTIterator
	{
		typedef HashNode<V> Node;
		typedef __HTIterator<K, V, Ref, Ptr, KeyofT, HashFunc> Self;

		Node* _node;
		HashTable<K, V, KeyofT, HashFunc>* _pht;
	public:
		__HTIterator(Node* node, HashTable<K, V, KeyofT, HashFunc>* pht)
			:_node(node)
			,_pht(pht)
		{}
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}
		Self& operator++()
		{
			if (_node->next)//下一个节点不为空
			{
				_node = _node->next;
			}
			else
			{
				KeyofT kot;
				HashFunc hf;
				size_t index = hf(kot(_node->_data)) % _pht->_ht.size();
				++index;
				while ( index< _pht->_ht.size() && _pht->_ht[index] == nullptr)
				{
					index++;
				}
				if (index == _pht->_ht.size())//走到最后也没找到
					_node = nullptr;
				else
					_node = _pht->_ht[index];
				return *this;
			}
		}
		bool operator!=(const Self& s)const
		{
			return _node != s._node;
		}
		bool operator==(const Self& s)const
		{
			return _node == s._node;
		}
	};

1.4 表

        构造和析构是典型的链表操作,只要知道哈希表中的每一个位置都存储着链表头,执行相应操作即可。begin是哈希表中第一个不为空位置的第一个节点构造的迭代器,end就简单使用nullptr构造迭代器。表中其他插入、删除等各个接口的实现就不予具体说明了。

	template<class K, class V,class KeyofT, class HashFunc = Hash<K>>
	class HashTable
	{
		typedef HashNode<V> Node;
		template<class K, class V, class Ref, class Ptr, class KeyOfT, class HashFunc>
		friend struct __HTIterator;
		typedef HashTable<K, V, KeyofT, HashFunc> Self;
	public:
		typedef __HTIterator<K, V, V&, V*, KeyofT, HashFunc> iterator;
		
		HashTable(){}//HashTable() = default;
		HashTable(const Self& HT)
		{
			_ht.resize(HT._ht.size());
			for (size_t i = 0; i < HT._ht.size(); i++)
			{
				Node* cur = HT._ht[i];
				while (cur)
				{
					Node* copy = new Node(cur->_data);
					copy->next = _ht[i];
					_ht[i] = copy;
					cur = cur->next;
				}
			}
		}
		Self& operator=(Self copy)
		{
			std::swap(_size, copy._size);
			_ht.swap(copy._ht);
			return *this;
		}
		~HashTable()
		{
			for (size_t i = 0; i < _ht.size(); i++)
			{
				Node* cur = _ht[i];
				while (cur)
				{
					Node* next = cur->next;
					delete cur;
					cur = next;
				}
				_ht[i] = nullptr;
			}
		}
		iterator begin()
		{
			for (int i = 0; i < _ht.size(); i++)
			{
				if (_ht[i])
				{
					return iterator(_ht[i],this);
				}
			}
			return end();
		}
		iterator end()
		{
			return iterator(nullptr, this);
		}
		// 插入
		std::pair<iterator,bool> Insert(const V& data)
		{
			KeyofT kot;
			iterator ret = Find(kot(data));
			if (ret!=end())
			{
				return std::make_pair(ret,false);
			}
			if (_ht.size() == _size)//负载因子到1
			{
				//扩容
				int newsize = _ht.size() == 0 ? 10 : _ht.size() * 2;
				std::vector<Node*> newTable;
				newTable.resize(newsize);
				//重新装入
				for (int i = 0; i < _ht.size(); i++)
				{
					Node* cur = _ht[i];
					while (cur)
					{
						Node* next = cur->next;
						Hash<K> hs;
						size_t index = hs(kot(_ht[i]->_data))
							% newTable.size();
						cur->next = newTable[index];
						newTable[index] = cur;

						cur = next;
					}
					_ht[i] = nullptr;
				}
				_ht.swap(newTable);
			}
			Hash<K> hs;
			size_t index = hs(kot(data)) % _ht.size();
			Node* newNode = new Node(data);
			newNode->next = _ht[index];
			_ht[index] = newNode;
			++_size;
			return std::make_pair(iterator(newNode,this), false);
		}
		// 查找
		iterator Find(const K& key)
		{
			if (_ht.empty())
				return end();
			Hash<K> hs;
			size_t index = hs(key) % _ht.size();
			Node* cur = _ht[index];
			while (cur)
			{
				KeyofT kot;
				if (kot(cur->_data) == key)
					return iterator(cur,this);
				cur = cur->next;
			}
			return end();
		}
		// 删除
		bool Erase(const K& key)
		{
			if (_ht.empty())
				return false;
			Hash<K> hs;
			size_t index = hs(key) % _ht.size();
			Node* cur = _ht[index];
			Node* pre = nullptr;
			while (cur)
			{
				KeyofT kot;
				if (kot(cur->data) == key) 
				{
					if (pre == nullptr)//头删
						_ht[index] = cur->next;
					else
						pre->next = cur->next;
					delete cur;
					--_size;
					return true;
				}
				pre = cur;
				cur = cur->next;
			}
			return false;
		}
		size_t Size()const
		{
			return _size;
		}
		bool Empty() const
		{
			return _size == 0;
		}
	private:
		std::vector<Node*> _ht;
		size_t _size = 0;//有效数据的个数
	};
}

2 unordered_map

        按要求完成仿函数,由于map传入的是键值对,在下一层的表中只需要取键即可。operator[]在map中也是这么实现的,利用插入函数中就包含了查找的特性,调用插入函数,获得返回值的内容即可完成[]的重载。

#pragma once
#include "Open_Hash.h"
using namespace Open_Hash;

namespace lwh
{
	template<class K, class V, class HashFunc = Hash<K>>
	class unordered_map
	{
		struct MapKeyOfT
		{
			const K& operator()(const std::pair<K,V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename HashTable<K, std::pair<K,V>, MapKeyOfT, HashFunc>::iterator iterator;
		iterator begin()
		{
			return _HT.begin();
		}
		iterator end()
		{
			return _HT.end();
		}
		std::pair<iterator,bool> insert(const std::pair<K, V> kv)
		{
			return _HT.Insert(kv);
		}
		V& operator[](const K& key)
		{
			
			return _HT.Insert(make_pair(key, V())).first->second;
		}
	private:
		HashTable<K, std::pair<K,V>, MapKeyOfT, HashFunc> _HT;
	};
}

3 unordered_set

#pragma once
#include "Open_Hash.h"
using namespace Open_Hash;
namespace lwh
{
	template<class K, class HashFunc = Hash<K>>
	class unordered_set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename HashTable<K, K, SetKeyOfT, HashFunc>::iterator iterator;
		iterator begin()
		{
			return _HT.begin();
		}
		iterator end()
		{
			return _HT.end();
		}
		std::pair<iterator, bool>  insert(const K key)
		{
			return _HT.Insert(key);
		}
	private:
		HashTable<K,K, SetKeyOfT, HashFunc> _HT;
	};
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值