C++ 简单实现unorderset和unordermap

unorderset和unordermap是C++11中心引入的一种关联式容器。set和map与他们之间的不同之处就是遍历时是否有序,通过名字就可以看出,unorderset和unordermap在遍历时是无序的。之所他们有这样的差异,是因为他们底层的实现的数据结构是不同的,unorderset和unordermap底层是通过哈希表来实现的,而set和map底层是通过红黑树来实现的。unorderset和unordermap的插入和查找的效率非常高,这也会引入他们的原因之一。下面我们一起来看看如何实现的

看该文时,你有必要先了解哈希
数据结构 5分钟带你搞定哈希表(建议收藏)!!!

改造哈希表

如果你知道如何实现哈希表后,其实unorderset的实现也实现一半了,当然,这里只是简单的实现,和STL库的底层实现还是有一点差别的。首先我们必须要对哈希表进行封装,这里我就直接提供代码,代码和上一篇文章代码类似,只是加了模板和伪函数,该伪函数就是通过val来获取key,用key来作为比较来存储

迭代器

哈希表中主要成员是指针数组,我们要通过封装该指针数组,来实现迭代器。我们先明白begin()和end()的位置。begin()应该要是第一个非空链表的头结点,而end()应该最后一个节点的下一个位置,这里则指的是nullptr
在这里插入图片描述
迭代器最难实现的就是迭代器的++操作,应为是链表,我们不能单词的进行++操作,也就是通过封装结点后,然后对++操作符进行重载来实现的。实现++操作时,有两种可能,第一种是存在next结点,第二种是不存在next结点,存在next结点则让结点直接置为next结点,不存在则需要利用哈希表中的指针数组来获得当前结点的哈希位置,然后去查找下一个非空的链表头结点,找到则将结点置为所找到的头结点,找不到则返回空,表示结束。由于我们用到了哈希表中的私有成员,我们需要将迭代器类设置为哈希表类的友元类。

#include <vector>
#include <iostream>
using namespace std;

template<class K, class V, class KeyOfValue>
class HTable;//声明

template<class V>
struct HashNode
{
	typedef HashNode<V> Node;
	V _val;
	Node* _next;

	HashNode(const V& val)
		:_val(val)
		,_next(nullptr)
	{}
};


template<class K, class V, class KeyOfValue>
struct HashIterator
{
	typedef HashNode<V> Node;
	typedef HashIterator<K, V, KeyOfValue> Self;
	typedef HTable<K, V, KeyOfValue> HT;
	Node* _node;
	HT* _hPtr;

	HashIterator(Node* node, HT* hPtr)
		:_node(node)
		,_hPtr(hPtr)
	{}

	V& operator*()
	{
		return _node->_val;
	}

	V* operator->()
	{
		return &_node->_val;
	}

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

	Self& operator++()
	{
		//下一个结点存在
		if (_node->_next)
		{
			_node = _node->_next;
		}
		else//不存在下一个节点
		{
			//则需要找到下一个非空的链表的头结点
			//计算当前节点在哈希表中的位置
			KeyOfValue kov;
			size_t idx = kov(_node->_val) % _hPtr->_ht.size();
			//从下一个哈希位置开始查找
			++idx;
			for (; idx < _hPtr->_ht.size(); ++idx)
			{
				if (_hPtr->_ht[idx])//找到下一个非空结点
				{
					_node = _hPtr->_ht[idx];
					break;
				}
			}
			//没找到非空链表,则表示走到末尾,则为空
			if (idx == _hPtr->_ht.size())
				_node = nullptr;
		}
		return *this;
	}

};

template<class K, class V, class KeyOfValue>
class HTable
{
public:
	typedef HashIterator<K, V, KeyOfValue> iterator;
	typedef HashNode<V> Node;

	template<class K, class V, class KeyOfValue>
	friend struct HashIterator;

	HTable(int n = 10)
		:_ht(n)
		,_size(0)
	{}

	iterator begin()
	{
		//第一个非空链表的头结点
		for (size_t i = 0; i < _ht.size(); ++i)
		{
			if (_ht[i])
			{
				return iterator(_ht[i], this);
			}
		}
		return iterator(nullptr, this);
	}

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

	pair<iterator, bool> insert(const V& val)
	{
		//0.检查容量
		checkCapacity();

		//1.计算hash位置
		KeyOfValue kov;
		int idx = kov(val) % _ht.size();

		//2.查找
		Node* cur = _ht[idx];
		while (cur)
		{
			if (kov(cur->_val) == kov(val))
				return make_pair(iterator(cur, this), false);
			cur = cur->_next;
		}

		//3.插入--头插
		cur = new Node(val);
		cur->_next = _ht[idx];
		_ht[idx] = cur;
		++_size;
		return make_pair(iterator(cur, this), true);
	}

	void checkCapacity()
	{
		if (_size == _ht.size())
		{
			int newC = _size == 0 ? 10 : 2 * _size;

			//创建新的指针数组
			vector<Node*> newHt(newC);

			KeyOfValue kov;
			//遍历旧表
			for (size_t i = 0; i < _ht.size(); ++i)
			{
				Node* cur = _ht[i];
				//遍历单链表
				while (cur)
				{
					Node* next = cur->_next;
					//计算新的位置
					int idx = kov(cur->_val) % newHt.size();
					//头插
					cur->_next = newHt[idx];
					newHt[idx] = cur;

					cur = next;
				}
				//旧表指针置空
				_ht[i] = nullptr;
			}

			//交换新表和旧表
			swap(_ht, newHt);
		}
	}
private:
	//指针数组
	vector<Node*> _ht;
	int _size;
};

unorderedset实现

template<class K>
class UnorderedSet
{
	struct SetKeyOfValue
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	typedef typename HTable<K, K, SetKeyOfValue>::iterator iterator;
	pair<iterator, bool> insert(const K& key)
	{
		return _ht.insert(key);
	}

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

	iterator end()
	{
		return _ht.end();
	}
private:
	HTable<K, K, SetKeyOfValue> _ht;
};

测试:
在这里插入图片描述

unorderedmap实现

template<class K, class V>
class UnorderedMap
{
	struct MapKeyOfValue
	{
		const K& operator()(const pair<K, V>& val)
		{
			return val.first;
		}
	};
public:
	typedef typename HTable<K, pair<K, V>, MapKeyOfValue>::iterator iterator;
	
	pair<iterator, bool> insert(const pair<K, V>& val)
	{
		return _ht.insert(val);
	}
	iterator begin()
	{
		return _ht.begin();
	}

	iterator end()
	{
		return _ht.end();
	}
	V& operator[](const K& key)
	{
		pair<iterator, bool> ret = _ht.insert(make_pair(key, V()));
		return ret.first->second;
	}
private:
	HTable<K, pair<K, V>, MapKeyOfValue> _ht;
};

测试:
在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

WhiteShirtI

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

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

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

打赏作者

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

抵扣说明:

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

余额充值