STL容器 —— unorder_map和unorder_set的模拟实现


前言:unorder系列的关联式容器,底层用的是哈希桶来实现的,本章就会用哈希桶来模拟实现unorder_map和unorder_set,里面的关键就是 在于迭代器的实现。


1. 底层哈希桶的实现(支持迭代器)

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

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

template<>
struct Hash<string>
{
	size_t operator()(const string& key)
	{
		size_t value = 0;
		for (auto ch : key)
		{
			value *= 31;
			value += ch;
		}
		return value;
	}
};



namespace link_hash_table
{
	template<class T>
	struct HashNode;
	template<class K, class T, class keyofT, class Hashfunc>
	class link_hashtable;


	template<class K, class T, class ref,class ptr,class keyofT, class Hashfunc = Hash<K>>
	struct __HIterator
	{
		typedef HashNode<T> Node;
		typedef	__HIterator<K, T, ref, ptr, keyofT, Hashfunc> self;

		Node* _node;
		link_hashtable<K, T, keyofT, Hashfunc>* _hash_table;

		__HIterator(HashNode<T>* Node, link_hashtable<K, T, keyofT, Hashfunc>* hashtable)
			:_node(Node),
			_hash_table(hashtable)
		{
		}

		ref operator*()
		{
			return _node->_date;
		}

		ptr operator->()
		{
			return &_node->_date;
		}

		self& operator++()
		{
			if (_node->_next)
			{
				_node = _node->_next;
			}
			else
			{
				keyofT kf;
				Hashfunc hf;

				size_t index = hf(kf(_node->_date)) % _hash_table->_tables.size();
				size_t i = 0;
				for (i = index + 1; i < _hash_table->_tables.size(); i++)
				{
					if (_hash_table->_tables[i] != nullptr)
					{
						_node = _hash_table->_tables[i];
						break;
					}
				}

				if (i == _hash_table->_tables.size())
				{
					_node = nullptr;
				}
			}

			return *this;
		}

		bool operator != (const self& op)
		{
			if (this->_node != op._node)
				return true;
			else
			{
				return false;
			}
		}

		bool operator == (const self& op)
		{
			if (this->_node == op._node)
				return true;
			else
			{
				return false;
			}
		}

	};


	template<class T>
	struct HashNode
	{
		T _date;
		HashNode<T>* _next;

		HashNode(const T& date)
			:_date(date),
			_next(nullptr)
		{
		}
	};


	template<class K,class T,class keyofT,class Hashfunc>
	class link_hashtable
	{
		typedef HashNode<T> Node;
		template<class K, class T, class Ref, class Ptr, class KeyOfT, class HashFunc>
		friend struct __HIterator;
	public:
		typedef __HIterator<K, T, T&, T*, keyofT, Hashfunc> iterator;

	private:
		vector<Node*> _tables;
		size_t _n = 0;
	public:

		iterator begin()
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				if (_tables[i] != nullptr)
					return iterator(_tables[i], this);
			}

			return end();
		}

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

		Node* find(const K& key)
		{
			if (_tables.size() == 0)
				return nullptr;

			Hashfunc hf;
			keyofT kf;

			size_t index = hf(key) % _tables.size();
			Node* cur = _tables[index];

			while (cur)
			{
				if (kf(cur->_date)== key)
					return cur;
				else
					cur = cur->_next;
			}

			return nullptr;
		}

		bool erase(const K& key)
		{
			Node* ret = find(key);
			if (ret == nullptr)
			{
				return false;
			}

			Hashfunc hf;
			keyofT kf;
			size_t index = hf(key) % _tables.size();

			Node* pre = nullptr;
			Node* cur = _tables[index];

			while (cur)
			{
				Node* next = cur->_next;

				if (kf(cur->_date) == key)
				{
					if (pre == nullptr)
					{
						_tables[index] = next;
					}
					else
					{
						pre->_next = next;
					}
					_n -= 1;
					delete cur;
					return true;
				}
				else
				{
					pre = cur;
					cur = next;
				}
			}

			return false;

		}

		bool insert(const T& kv)
		{
			Hashfunc hf;
			keyofT kf;

			Node* ret = find(kf(kv));
			if (ret)
			{
				return false;
			}


			if (_n == _tables.size())
			{
				size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;

				vector<Node*> newTables;
				newTables.resize(newSize);

				for (size_t i = 0; i < _tables.size(); ++i)
				{
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;

						size_t index = hf(kf(cur->_date)) % newTables.size();
						// 头插
						cur->_next = newTables[index];
						newTables[index] = cur;

						cur = next;
					}

					_tables[i] = nullptr;
				}

				_tables.swap(newTables);
			}

			size_t index = hf(kf(kv)) % _tables.size();
            
			Node* newnode = new Node(kv);
			newnode->_next = _tables[index];
			_tables[index] = newnode;
			_n += 1;
		}

	};
}

以上的哈希桶是支持迭代器的,迭代器的 * -> == != 都是简单的,难点在于 ++。

  • 哈希桶的下一个节点不为空,那还好,就直接跳到下一个节点;
  • 哈希桶的下一个节点为空,那就需要跳到下一个桶中。要是后面的桶都为空,那么就使得++后的结果为空,就好了。

2. unorder_map的实现

    template<class K,class V,class hash = Hash<K>>
	class unorder_map
	{
		struct keyofmap
		{
			const K& operator()(const pair<K,V>& kv)
			{
				return kv.first;
			}
		};

	private:
		link_hash_table::link_hashtable<K, pair<K, V>, keyofmap, hash> _ht;

	public:

		typedef typename link_hash_table::link_hashtable<K, pair<K,V>, keyofmap, hash>::iterator iterator;

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

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

		bool insert(const pair<K,V>& kv)
		{
			return _ht.insert(kv);
		}

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

	};

3. unorder_set的模拟实现

     template<class K,class hash = Hash<K>>
	 class unorder_set 
	 {
		 struct keyofset
		 {
			 const K& operator()(const K& key)
			 {
				 return key;
			 }
		 };

	 private:
		 link_hash_table::link_hashtable<K, K, keyofset, hash> _ht;
	 public:

		typedef typename link_hash_table::link_hashtable<K, K, keyofset, hash>::iterator iterator;

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

		iterator end()
		{
			return _ht.end();
		}
		 bool insert(const K& kv)
		 {
			 return _ht.insert(kv);
		 }

		 bool erase(const K& kv)
		 {
			 return _ht.erase(kv);
		 }
	 };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

动名词

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

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

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

打赏作者

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

抵扣说明:

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

余额充值