【C++/STL】哈希表的模拟实现+封装

HashTable.h

cpp 复制代码
#pragma once
//顺序:
//1.哈希表
//2.封装map和set
//3.普通迭代器
//4.const迭代器
//5.insert返回值 operator[]
//6.key不能修改的问题
#include <vector>
#include <string>
namespace Hashbucket
{
	template<class K>
	struct DefaultHashfunc
	{
		size_t operator()(const K& key)
		{
			return (size_t)key;
		}
	};

	template<>
	struct DefaultHashfunc<string>//模板的特化
	{
		size_t operator()(const string& str)
		{
			size_t hash = 0;
			for (auto ch : str)
			{
				hash *= 131;
				hash += ch;
			}
			return hash;
		}
	};
	template<class T>
	struct HashNode
	{
		HashNode<T>* _next;
		T _data;
		HashNode(const T& data)
			:_data(data)
			, _next(nullptr)
		{}
	};

	template<class K, class T, class KeyOfT, class HashFunc>
	class HashTable;
	//声明和定义一般缺省值只能给其中一个。
	template<class K,class T, class Ptr, class Ref, class KeyOfT,class HashFunc>
	struct HTIterator
	{
		typedef HashNode<T> Node;
		typedef HTIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;
		typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> Iterator;

		Node* _node;
		/*HashTable<K, T, KeyOfT, HashFunc>* _pht;*/
		//下面这行为什么要加const?!
		const HashTable<K, T, KeyOfT, HashFunc>* _pht;
		//为什么一定要传哈希表的指针?!!
		HTIterator(Node* node,const HashTable<K, T, KeyOfT, HashFunc>* pht)
			:_node(node)
			,_pht(pht)
		{ }

		//==================================================
		//传的是普通迭代器时,它是拷贝构造
		//传的是const迭代器时,它是构造函数
		HTIterator(const Iterator& it)
			:_node(it._node)
			,_pht(it._pht)
		{ }
		//==================================================
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}
		bool operator!=(const Self& s)
		{
			return _node != s._node;
		}
		bool operator==(const Self& s)
		{
			return _node == s._node;
		}
		Self& operator++()
		{
			if (_node->_next)
			{
				_node = _node->_next;
				//当前桶还没完
			}
			else
			{
				KeyOfT kot;
				HashFunc hf;
				size_t hashi = hf(kot(_node->_data)) % _pht->_table.size();
				++hashi;
				//查找下一个不为空的桶
				while (hashi < _pht->_table.size())
				{
					if (_pht->_table[hashi])
					{
						_node = _pht->_table[hashi];
						return *this;
					}
					else
					{
						hashi++;
					}
				}
				//没找到:
				_node = nullptr;
			}
			return *this;//适用于桶还没完和没找到下一个的情况。
		}
		Self& operator--()
		{
			//???
		}
	};

	template<class K, class T, class KeyOfT, class HashFunc = DefaultHashfunc<K>>
	class HashTable
	{
		typedef HashNode<T> Node;
		//友元声明
		template<class K,class T, class Ptr, class Ref,class KeyOfT,class HashFunc>
		friend struct HTIterator;
	public:
		typedef HTIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;
		typedef HTIterator<K, T,const T*,const T&, KeyOfT, HashFunc> const_iterator;
		iterator begin()
		{
			//找第一个桶
			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				if (cur)
				{
					return iterator(cur, this);
				}
			}
			return iterator(nullptr, this);
		}
		iterator end()
		{
			return iterator(nullptr, this);
		}
		const_iterator begin() const
		{
			//找第一个桶
			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				if (cur)
				{
					return const_iterator(cur, this);
				}
			}
			return const_iterator(nullptr, this);
		}
		const_iterator end() const
		{
			return const_iterator(nullptr, this);
		}
		HashTable()
		{
			_table.resize(10, nullptr);
		}
		~HashTable()
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				while (cur)
				{
					Node* next = cur->_next;
					delete cur;
					cur = next;
				}
				_table[i] = nullptr;
			}
		}
		pair<iterator,bool> Insert(const T& data)
		{
			KeyOfT kot;
			iterator it = Find(kot(data));
			if (it!=end())
			{
				return make_pair(it,false);
			}
			HashFunc hf;
			if (_n == _table.size())
			{
				size_t newSize = _table.size() * 2;
				HashTable<K, T,KeyOfT,HashFunc> newHT;
				newHT._table.resize(newSize, nullptr);
				for (size_t i = 0; i < _table.size(); i++)
				{
					Node* cur = _table[i];
					while (cur)
					{
						Node* next = cur->_next;
						//头插到新表
						size_t hashi = hf(kot(cur->_data)) % newHT._table.size();
						cur->_next = newHT._table[hashi];
						newHT._table[hashi] = cur;

						cur = next;
					}
					_table[i] = nullptr;
				}
				_table.swap(newHT._table);
			}
			size_t hashi = hf(kot(data)) % _table.size();
			//头插
			Node* newnode = new Node(data);
			newnode->_next = _table[hashi];
			_table[hashi] = newnode;
			_n++;
			//return make_pair(&_table[hashi],true);
			//要返回的值里有iterator类型,是HTIterator类typedef后的结果,类中
			//有两个值:Node*和哈希表的指针,所以不能只返回新插入的那个节点的指针
			//要构造iterator类型再返回,如下:
			return make_pair(iterator(newnode, this), true);
			//this为指向当前HashTable对象的指针。
		}
		iterator Find(const K& key)
		{
			HashFunc hf;
			KeyOfT kot;
			//形参已经是K类型了,无需取出
			//size_t hashi = hf(kot(key)) % _table.size();
			size_t hashi = hf(key) % _table.size();
			Node* cur = _table[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					return iterator(cur,this);
				}
				cur = cur->_next;
			}
			return iterator(nullptr,this);
		}
		bool Erase(const K& key)
		{
			HashFunc hf;
			KeyOfT kot;
			size_t hashi = hf(key) % _table.size();
			Node* prev = nullptr;
			Node* cur = _table[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						_table[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					//执行到这里时说明已找到要删的值并且已删除。
					_n--;
					delete cur;
					return true;
				}
				prev = cur;
				cur = cur->_next;
			}
			return false;
		}
		void Print()
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				printf("[%d]->", i);
				Node* cur = _table[i];
				while (cur)
				{
					cout << cur->_data<< "->";
					cur = cur->_next;
				}
				printf("NULL\n");
			}
			cout << endl;
		}
	private:
		vector<Node*> _table;
		size_t _n = 0;
	};
}

UnorderedMap.h

cpp 复制代码
#pragma once
#include "HashTable.h"
namespace Q
{
	template<class K,class V>
	class unordered_map
	{
		struct MapKeyOfT
		{
			//const K& operator()(const pair<K, V>& kv) const ai改法
			//???
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename Hashbucket::HashTable<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
		typedef typename Hashbucket::HashTable<K, pair<const K, V>, MapKeyOfT>::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 pair<K, V>& kv)
		{
			return _ht.Insert(kv);
		}
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _ht.Insert(make_pair(key,V()));
			return ret.first->second;
		}
	private:
		Hashbucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;
	};
}

UnorderedSet.h

cpp 复制代码
#pragma once
#include "HashTable.h"
namespace Q
{
	template<class K>
	class unordered_set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename Hashbucket::HashTable<K, K, SetKeyOfT>::const_iterator iterator;
		typedef typename Hashbucket::HashTable<K, K, SetKeyOfT>::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<const_iterator, bool> insert(const K& key)
		{
			pair<typename Hashbucket::HashTable<K, K, SetKeyOfT>::iterator, bool> ret = _ht.Insert(key);
			return pair<const_iterator, bool>(ret.first, ret.second);
		}
		/*bool insert(const K& key)
		{
			return _ht.Insert(key);
		}*/
	private:
		Hashbucket::HashTable<K, K, SetKeyOfT> _ht;

	};
}

test.cpp

cpp 复制代码
#include <iostream>
using namespace std;
#include "HashTable.h"
#include "UnorderedSet.h"
#include "UnorderedMap.h"
int main()
{
	Q::unordered_set<int> us;
	us.insert(5);
	us.insert(8);
	us.insert(2);
	us.insert(3);
	us.insert(1);

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

	Q::unordered_map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("left", "左边"));
	dict.insert(make_pair("insert", "插入"));
	dict.insert(make_pair("xxxx", "yyy"));

	for (auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	return 0;
}
相关推荐
骁的小小站6 小时前
Verilator 和 GTKwave联合仿真
开发语言·c++·经验分享·笔记·学习·fpga开发
旭意10 小时前
C++蓝桥杯之结构体10.15
开发语言·c++
深思慎考11 小时前
调用百度云语音识别服务——实现c++接口识别语音
c++·语音识别·百度云
K 旺仔小馒头13 小时前
优选算法:01 双指针巧解移动零问题
c++·算法·刷题
AlexMercer101213 小时前
Ubuntu从零开始配置Git
c++·git·ubuntu·gitee
无敌最俊朗@14 小时前
C++ STL Deque 高频面试题与答案
开发语言·c++
和编程干到底15 小时前
C++基础
开发语言·c++
John.Lewis16 小时前
C++初阶(14)list
开发语言·c++·笔记
hsjkdhs17 小时前
C++文件操作
开发语言·c++