C++进阶:哈希表封装unordered_map和unordered_set(模拟实现)

发布于:2024-06-03 ⋅ 阅读:(81) ⋅ 点赞:(0)

基于开散列封装哈希表:

HashTable.h

#pragma once
#include<vector>

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

// 特化
template<>
struct HashFunc<string>
{
	// abcd
	// bcad
	// aadd
	// BKDR
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (auto ch : key)
		{
			hash *= 131;
			hash += ch;
		}

		return hash;
	}
};


namespace hash_bucket
{
	template<class T>
	struct HashNode
	{
		T _data;
		HashNode<T>* _next;

		HashNode(const T& data)
			:_data(data)
			, _next(nullptr)
		{}
	};

	// 前置声明
	template<class K, class T, class KeyOfT, class Hash>
	class HashTable;

	//template<class K, class T, class KeyOfT, class Hash>
	//struct __HTIterator
	//{
	//	typedef HashNode<T> Node;
	//	typedef __HTIterator<K, T, KeyOfT, Hash> Self;

	//	Node* _node;
	//	HashTable<K, T, KeyOfT, Hash>* _pht;

	//	__HTIterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
	//		:_node(node)
	//		,_pht(pht)
	//	{}

	//	T& operator*()
	//	{
	//		return _node->_data;
	//	}

	//	Self& operator++()
	//	{
	//		if (_node->_next)
	//		{
	//			// 当前桶没走完,找当前桶的下一个节点
	//			_node = _node->_next;
	//		}
	//		else
	//		{
	//			// 当前桶走完了,找下一个不为空的桶的第一个节点
	//			KeyOfT kot;
	//			Hash hs;
	//			size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
	//			++i;
	//			for (; i < _pht->_tables.size(); i++)
	//			{
	//				if (_pht->_tables[i])
	//					break;
	//			}

	//			if (i == _pht->_tables.size())
	//			{
	//				// 所有桶都走完了,最后一个的下一个用nullptr标记
	//				_node = nullptr;
	//			}
	//			else
	//			{
	//				_node = _pht->_tables[i];
	//			}
	//		}

	//		return *this;
	//	}

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

	template<class K, class T, class KeyOfT, class Hash>
	class HashTable
	{
		typedef HashNode<T> Node;
	public:
		// 友元声明
		/*template<class K, class T, class KeyOfT, class Hash>
		friend struct __HTIterator;*/

		// 内部类
		template<class Ptr, class Ref>
		struct __HTIterator
		{
			typedef HashNode<T> Node;
			typedef __HTIterator Self;

			Node* _node;
			const HashTable* _pht;

			__HTIterator(Node* node, const HashTable* 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;
					Hash hs;
					size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
					++i;
					for (; i < _pht->_tables.size(); i++)
					{
						if (_pht->_tables[i])
							break;
					}

					if (i == _pht->_tables.size())
					{
						// 所有桶都走完了,最后一个的下一个用nullptr标记
						_node = nullptr;
					}
					else
					{
						_node = _pht->_tables[i];
					}
				}

				return *this;
			}

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

		typedef __HTIterator<T*, T&> iterator;
		typedef __HTIterator<const T*, const T&> const_iterator;

		iterator begin()
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				if (cur)
				{
					// this -> HashTable*
					return iterator(cur, this);
				}
			}

			return end();
		}

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

		const_iterator begin() const
		{
			for (size_t i = 0; i < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				if (cur)
				{
					// this -> const HashTable*
					return const_iterator(cur, this);
				}
			}

			return end();
		}

		const_iterator end() const
		{
			return const_iterator(nullptr, this);
		}

		HashTable()
		{
			_tables.resize(10, nullptr);
			_n = 0;
		}



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

					cur = next;
				}

				_tables[i] = nullptr;
			}
		}

		pair<iterator, bool> Insert(const T& data)
		{
			KeyOfT kot;
			iterator it = Find(kot(data));
			if (it != end())
				return make_pair(it, false);

			Hash hs;
			// 扩容
			// 负载因子为1时扩容
			if (_n == _tables.size())
			{
				//HashTable<K, V> newHT;
				//newHT._tables.resize(_tables.size() * 2);

				 旧表重新计算负载到新表
				//for (size_t i = 0; i < _tables.size(); i++)
				//{
				//	Node* cur = _tables[i];
				//	while (cur)
				//	{
				//		newHT.Insert(cur->_kv);
				//		cur = cur->_next;
				//	}
				//}

				//_tables.swap(newHT._tables);

				vector<Node*> newTables(_tables.size() * 2, nullptr);
				for (size_t i = 0; i < _tables.size(); i++)
				{
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;
						// 头插新表的位置
						size_t hashi = hs(kot(cur->_data)) % newTables.size();
						cur->_next = newTables[hashi];
						newTables[hashi] = cur;

						cur = next;
					}

					_tables[i] = nullptr;
				}

				_tables.swap(newTables);
			}

			size_t hashi = hs(kot(data)) % _tables.size();
			Node* newnode = new Node(data);
			// 头插
			newnode->_next = _tables[hashi];
			_tables[hashi] = newnode;
			++_n;

			return make_pair(iterator(newnode, this), true);
		}

		iterator Find(const K& key)
		{
			KeyOfT kot;
			Hash hs;
			size_t hashi = hs(key) % _tables.size();
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					return iterator(cur, this);
				}

				cur = cur->_next;
			}

			return end();
		}

		bool Erase(const K& key)
		{
			KeyOfT kot;
			Hash hs;
			size_t hashi = hs(key) % _tables.size();
			Node* prev = nullptr;
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					// 删除的是第一个
					if (prev == nullptr)
					{
						_tables[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}

					delete cur;

					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}

			return false;
		}

	private:
		vector<Node*> _tables; // 指针数组
		size_t _n;

		//vector<list<pair<K, V>>> _tables;
	};

	//void TestHT1()
	//{
	//	int a[] = { 10001,11,55,24,19,12,31,4,34,44};
	//	HashTable<int, int> ht;
	//	for (auto e : a)
	//	{
	//		ht.Insert(make_pair(e, e));
	//	}

	//	ht.Insert(make_pair(32, 32));
	//	ht.Insert(make_pair(32, 32));

	//	ht.Erase(31);
	//	ht.Erase(11);
	//}

	//void TestHT2()
	//{
	//	HashTable<string, int> ht;
	//	ht.Insert(make_pair("sort", 1));
	//	ht.Insert(make_pair("left", 1));
	//	ht.Insert(make_pair("insert", 1));
	//}
}

基于哈希表实现unordered_set类

基于HashTable.h封装的哈希表类提供的接口,实现一个unordered_set类。

my_unordered_set.h

该文件基本实现了unordered_set类。

#pragma once

#include"HashTable.h"

namespace xx
{
	
	template<class K, class Hash = HashFunc<K>>
	class unordered_set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;
		typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::const_iterator const_iterator;


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

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

		const_iterator begin() const
		{
			return _ht.begin();
		}

		const_iterator end() const
		{
			return _ht.end();
		}

		pair<iterator, bool> insert(const K& key)
		{
			return _ht.Insert(key);
		}

		iterator find(const K& key)
		{
			return _ht.Find(key);
		}

		bool erase(const K& key)
		{
			return _ht.Erase(key);
		}
	private:
		hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
	};

	void Func(const unordered_set<int>& s)
	{
		unordered_set<int>::iterator it = s.begin();
		while (it != s.end())
		{
			//*it = 1;
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test_unordered_set()
	{
		unordered_set<int> s;
		s.insert(31);
		s.insert(11);
		s.insert(5);
		s.insert(15);
		s.insert(25);

		unordered_set<int>::iterator it = s.begin();
		while (it != s.end())
		{
			//*it = 1;
			cout << *it << " ";
			++it;
		}
		cout << endl;

		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}

基于哈希表实现unordered_map类

基于my_unordered_map.h封装的哈希表类提供的接口,实现一个unordered_map。unordered_map的值是一个键值对。

Myunordered_map.h

该文件基本实现了unordered_map类。

#pragma once

namespace xx
{
	template<class K, class V, class Hash = HashFunc<K>>
	class unordered_map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;
		iterator begin()
		{
			return _ht.begin();
		}

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

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

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

	private:
		hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
	};

	void test_unordered_map()
	{
		string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜",
	"苹果", "香蕉", "苹果", "香蕉","苹果","草莓", "苹果","草莓" };
		unordered_map<string, int> countMap;
		for (auto& e : arr)
		{
			countMap[e]++;
		}

		unordered_map<string, int>::iterator it = countMap.begin();
		while (it != countMap.end())
		{
			//it->first += 'x'; // key不能修改
			it->second += 1;  // value可以修改
			cout << it->first << ":" << it->second << endl;
			++it;
		}
		cout << endl;

		for (auto& kv : countMap)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}
}

源文件test.cpp:
 

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;


#include"HashTable.h"
#include"my_unordered_set.h"
#include"my_unordered_map.h"



int main()
{
	xx::test_unordered_map();
	return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到