当前位置:   article > 正文

【C++】哈希表的模拟实现及 unordered_set 和 unorderded_map 的封装_哈希set使用仿函数

哈希set使用仿函数

在这里插入图片描述

前言

上一篇文章中讲到了哈希的概念和STL中关于哈希容器的使用,并且在后面对开散列进行了模拟实现,那么在这一篇文章中在开散列的基础上进行改造成哈希表,并且在哈希表的基础上封装 unordered_set 和 unordered_map。


一、哈希表的模拟实现

1.1 哈希表的改造

1.1.1 模板参数列表的改造

K:表示关键码类型

T:不同容器V的类型不同,如果是unordered_map,K代表一个键值对,如果是unordered_set,T 为 K。

KOfT: 因为V的类型不同,通过value取key的方式就不同,详细见
unordered_map/set的实现

HF: 哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将Key转换为整形数字才能取模

template<class K, class T ,  class KOfT , class HF>
class hash_table;
  • 1
  • 2

1.1.2 增加迭代器操作

// 前置声明,否则后面的__HTIterator找不到hash_table
	template<class K, class T, class KOfT, class HF>
	class hash_table;

	template<class K, class T , class Ref, class Ptr, class KOfT, class HF>
	struct __HTIterator
	{
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, Ref , Ptr , KOfT, HF> self;

		// 成员变量
		Node* _node;
		// 由于const迭代器中const修饰this
		// 所以这里需要加const,否则会导致权限放大
		// 编译无法通过的情况
		const hash_table<K, T, KOfT, HF>* _pht;
		// 
		size_t hashi;

		// 构造函数
		__HTIterator(Node* node, hash_table<K, T, KOfT, HF>* pht , size_t i)
			:_node(node)
			,_pht(pht)
			,hashi(i)
		{}

		// 构造函数
		__HTIterator(Node* node, const hash_table<K, T, KOfT, HF>* pht, size_t i)
			:_node(node)
			, _pht(pht)
			, hashi(i)
		{}

		self& operator++()
		{
			if (_node->_next)
			{
				// 若当前桶其他节点没有走完
				// 那么继续走下一个节点
				_node = _node->_next;
			}
			else
			{
				// 若当前桶的所有节点都已经走完
				// 那么继续向下一个桶不为空的桶走
				hashi++;
				while (hashi < _pht->_table.size())
				{
					if (_pht->_table[hashi])
					{
						_node = _pht->_table[hashi];
						break;

					}

					hashi++;
				}

				if (hashi == _pht->_table.size())
					_node = nullptr;
			}

			return *this;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
	};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

1.2 哈希表的模拟实现

1.2.1 哈希表中仿函数的实现

若存储key的类型不是整形时,需要将其转化为整数,整形不需要处理,日常中我们最常用到的类型是string,那么这里就写一个string转化为整形的版本。

// 整数类型
template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

// 特化
template<>
struct HashFunc<string>
{
	size_t operator()(const string& s)
	{
		size_t sum = 0;
		for (size_t i = 0; i < s.size(); i++)
		{
			sum = sum * 31 + s[i];
		}
		return sum;
	}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

1.2.2 哈希表中节点类的实现

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

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

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

1.2.3 哈希表中迭代器类的实现

namespace hash_bucket
{
	// 前置声明,否则后面的__HTIterator找不到hash_table
	template<class K, class T, class KOfT, class HF>
	class hash_table;

	template<class K, class T, class Ref, class Ptr, class KOfT, class HF>
	struct __HTIterator
	{
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, Ref, Ptr, KOfT, HF> self;

		// 成员变量
		Node* _node;
		// 由于const迭代器中const修饰this
		// 所以这里需要加const,否则会导致权限放大
		// 编译无法通过的情况
		const hash_table<K, T, KOfT, HF>* _pht;
		// 
		size_t hashi;

		// 构造函数
		__HTIterator(Node* node, hash_table<K, T, KOfT, HF>* pht, size_t i)
			:_node(node)
			, _pht(pht)
			, hashi(i)
		{}

		// 构造函数
		__HTIterator(Node* node, const hash_table<K, T, KOfT, HF>* pht, size_t i)
			:_node(node)
			, _pht(pht)
			, hashi(i)
		{}

		self& operator++()
		{
			if (_node->_next)
			{
				// 若当前桶其他节点没有走完
				// 那么继续走下一个节点
				_node = _node->_next;
			}
			else
			{
				// 若当前桶的所有节点都已经走完
				// 那么继续向下一个桶不为空的桶走
				hashi++;
				while (hashi < _pht->_table.size())
				{
					if (_pht->_table[hashi])
					{
						_node = _pht->_table[hashi];
						break;

					}

					hashi++;
				}

				if (hashi == _pht->_table.size())
					_node = nullptr;
			}

			return *this;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

1.2.4 哈希表中构造函数、析构函数和 Clear() 函数的实现

namespace hash_bucket
{
	template<class K, class T, class KOfT, class HF>
	class hash_table
	{
	public:
		typedef HashNode<T> Node;

	public:
		// 构造函数
		hash_table(int n = 10)
			:_table(vector<Node*>(n))
			, _n(0)
		{}

		// 析构函数
		~hash_table()
		{
			Clear();
		}

		void Clear()
		{
			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;
			}
		}

	private:
		vector<Node*> _table;
		int _n;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

1.2.5 哈希表中Swap 和 Size 函数的实现

namespace hash_bucket
{
	template<class K, class T, class KOfT, class HF>
	class hash_table
	{
	public:

		size_t Size()
		{
			return _n;
		}

		void Swap(hash_table<K, T, KOfT, HF>& ht)
		{
			_table.swap(ht._table);
			swap(_n, ht._n);
		}

	private:
		vector<Node*> _table;
		int _n;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

1.2.6 哈希表中 begin 和 end 函数的实现

namespace hash_bucket
{
	template<class K, class T, class KOfT, class HF>
	class hash_table
	{
	public:
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, T&, T*, KOfT, HF> iterator;
		typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;

		// 将__HTIterator设置为hash_table的友元
		// 使__HTIterator可以访问hash_table的私有
		template<class K, class T, class Ref, class Ptr, class KOfT, class HF>
		friend struct __HTIterator;

	public:
		// 迭代器
		iterator begin()
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				if (_table[i])
					return iterator(_table[i], this, i);
			}

			return end();
		}

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

		const_iterator begin()const
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				if (_table[i])
					return const_iterator(_table[i], this, i);
			}

			return end();
		}

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

	private:
		vector<Node*> _table;
		int _n;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

1.2.7 哈希表中 Find 函数的实现

namespace hash_bucket
{
	template<class K, class T, class KOfT, class HF>
	class hash_table
	{
	public:
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, T&, T*, KOfT, HF> iterator;
		typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;

		// 将__HTIterator设置为hash_table的友元
		// 使__HTIterator可以访问hash_table的私有
		template<class K, class T, class Ref, class Ptr, class KOfT, class HF>
		friend struct __HTIterator;

	public:
		// 查找
		iterator Find(const K& key)
		{
			HF hf;
			KOfT koft;
			int hashi = hf(key) % _table.size();
			Node* cur = _table[hashi];
			while (cur)
			{
				if (koft(cur->_data) == key)
					return iterator(cur, this, hashi);

				cur = cur->_next;
			}

			// 找不到返回空
			return end();
		}

	private:
		vector<Node*> _table;
		int _n;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

1.2.8 哈希表中 Insert 和 Erase 函数的实现

namespace hash_bucket
{
	template<class K, class T, class KOfT, class HF>
	class hash_table
	{
	public:
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, T&, T*, KOfT, HF> iterator;
		typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;

		// 将__HTIterator设置为hash_table的友元
		// 使__HTIterator可以访问hash_table的私有
		template<class K, class T, class Ref, class Ptr, class KOfT, class HF>
		friend struct __HTIterator;

	public:
		// 插入
		pair<iterator, bool> Insert(const T& data)
		{
			HF hf;
			KOfT koft;

			iterator tmp = Find(koft(data));
			// 不允许有相同的值
			if (tmp != end())
				return make_pair(tmp, false);

			// 扩容
			if (_n == _table.size())
			{
				int newcapacity = 2 * _table.size();
				hash_table newtable(newcapacity);

				for (size_t i = 0; i < _table.size(); i++)
				{
					Node* cur = _table[i];

					while (cur)
					{
						Node* next = cur->_next;
						int hashi = hf(koft(cur->_data)) % newcapacity;

						cur->_next = newtable._table[hashi];
						newtable._table[hashi] = cur;
						cur = next;
					}

					_table[i] = nullptr;
				}
				_table.swap(newtable._table);
			}

			// 头插 
			int hashi = hf(koft(data)) % _table.size();
			Node* newnode = new Node(data);
			newnode->_next = _table[hashi];
			_table[hashi] = newnode;
			_n++;

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

		// 删除
		bool Erase(const K& key)
		{
			Node* tmp = Find(key);
			// 找不到则删除失败
			if (tmp == nullptr)
				return false;

			HF hf;
			KOfT koft;
			int hashi = hf(key) % _table.size();
			Node* prev = nullptr;
			Node* cur = _table[hashi];
			while (cur)
			{
				Node* next = cur->_next;
				if (koft(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						_table[hashi] = next;
					}
					else
					{
						prev->_next = next;
					}

					_n--;
					delete cur;
					return true;
				}
				else
				{
					prev = cur;
					cur = next;
				}
			}

			return false;
		}

	private:
		vector<Node*> _table;
		int _n;
	};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108

1.2.9 哈希表的整体实现

#pragma once

#include<iostream>
#include<string>
#include<vector>
#include<unordered_set>
#include<set>


using namespace std;

// 整数类型
template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

// 特化
template<>
struct HashFunc<string>
{
	size_t operator()(const string& s)
	{
		size_t sum = 0;
		for (size_t i = 0; i < s.size(); i++)
		{
			sum = sum * 31 + s[i];
		}
		return sum;
	}
};

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

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

	// 前置声明,否则后面的__HTIterator找不到hash_table
	template<class K, class T, class KOfT, class HF>
	class hash_table;

	template<class K, class T , class Ref, class Ptr, class KOfT, class HF>
	struct __HTIterator
	{
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, Ref , Ptr , KOfT, HF> self;

		// 成员变量
		Node* _node;
		// 由于const迭代器中const修饰this
		// 所以这里需要加const,否则会导致权限放大
		// 编译无法通过的情况
		const hash_table<K, T, KOfT, HF>* _pht;
		// 
		size_t hashi;

		// 构造函数
		__HTIterator(Node* node, hash_table<K, T, KOfT, HF>* pht , size_t i)
			:_node(node)
			,_pht(pht)
			,hashi(i)
		{}

		// 构造函数
		__HTIterator(Node* node, const hash_table<K, T, KOfT, HF>* pht, size_t i)
			:_node(node)
			, _pht(pht)
			, hashi(i)
		{}

		self& operator++()
		{
			if (_node->_next)
			{
				// 若当前桶其他节点没有走完
				// 那么继续走下一个节点
				_node = _node->_next;
			}
			else
			{
				// 若当前桶的所有节点都已经走完
				// 那么继续向下一个桶不为空的桶走
				hashi++;
				while (hashi < _pht->_table.size())
				{
					if (_pht->_table[hashi])
					{
						_node = _pht->_table[hashi];
						break;

					}

					hashi++;
				}

				if (hashi == _pht->_table.size())
					_node = nullptr;
			}

			return *this;
		}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
	};
	
	template<class K, class T ,  class KOfT , class HF>
	class hash_table
	{
	public:
		typedef HashNode<T> Node;
		typedef __HTIterator<K, T, T& , T* ,KOfT, HF> iterator;
		typedef __HTIterator<K, T, const T&, const T*, KOfT, HF> const_iterator;

		// 将__HTIterator设置为hash_table的友元
		// 使__HTIterator可以访问hash_table的私有
		template<class K, class T, class Ref, class Ptr, class KOfT, class HF>
		friend struct __HTIterator;

	public:
		// 构造函数
		hash_table(int n = 10)
			:_table(vector<Node*>(n))
			,_n(0)
		{}

		// 析构函数
		~hash_table()
		{
			Clear();
		}

		void Clear()
		{
			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;
			}
		}

		size_t Size()
		{
			return _n;
		}

		void Swap(hash_table<K,T,KOfT,HF>& ht)
		{
			_table.swap(ht._table);
			swap(_n, ht._n);
		}

		// 迭代器
		iterator begin()
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				if (_table[i])
					return iterator(_table[i], this, i);
			}

			return end();
		}

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

		const_iterator begin()const
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				if (_table[i])
					return const_iterator(_table[i], this, i);
			}

			return end();
		}

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

		// 插入
		pair<iterator,bool> Insert(const T& data)
		{
			HF hf;
			KOfT koft;

			iterator tmp = Find(koft(data));
			// 不允许有相同的值
			if (tmp != end())
				return make_pair(tmp,false);

			// 扩容
			if (_n == _table.size())
			{
				int newcapacity = 2 * _table.size();
				hash_table newtable(newcapacity);

				for (size_t i = 0; i < _table.size(); i++)
				{
					Node* cur = _table[i];

					while (cur)
					{
						Node* next = cur->_next;
						int hashi = hf(koft(cur->_data)) % newcapacity;

						cur->_next = newtable._table[hashi];
						newtable._table[hashi] = cur;
						cur = next;
					}

					_table[i] = nullptr;
				}
				_table.swap(newtable._table);
			}

			// 头插 
			int hashi = hf(koft(data)) % _table.size();
 			Node* newnode = new Node(data);
			newnode->_next = _table[hashi];
			_table[hashi] = newnode;
			_n++;

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

		// 删除
		bool Erase(const K& key)
		{
			Node* tmp = Find(key);
			// 找不到则删除失败
			if (tmp == nullptr)
				return false;

			HF hf;
			KOfT koft;
			int hashi = hf(key) % _table.size();
			Node* prev = nullptr;
			Node* cur = _table[hashi];
			while (cur)
			{
				Node* next = cur->_next;
				if (koft(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						_table[hashi] = next;
					}
					else
					{
						prev->_next = next;
					}

					_n--;
					delete cur;
					return true;
				}
				else
				{
					prev = cur;
					cur = next;
				}
			}

			return false;
		}

		// 查找
		iterator Find(const K& key)
		{
			HF hf;
			KOfT koft;
			int hashi = hf(key) % _table.size();
			Node* cur = _table[hashi];
			while (cur)
			{
				if (koft(cur->_data) == key)
					return iterator(cur,this,hashi);

				cur = cur->_next;
			}

			// 找不到返回空
			return end();
		}

		void Some()
		{
			size_t bucketSize = 0;
			size_t maxBucketLen = 0;
			size_t sum = 0;
			double averageBucketLen = 0;

			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				if (cur)
				{
					++bucketSize;
				}

				size_t bucketLen = 0;
				while (cur)
				{
					++bucketLen;
					cur = cur->_next;
				}

				sum += bucketLen;

				if (bucketLen > maxBucketLen)
				{
					maxBucketLen = bucketLen;
				}
			}

			averageBucketLen = (double)sum / (double)bucketSize;

			printf("all bucketSize:%d\n", _table.size());
			printf("bucketSize:%d\n", bucketSize);
			printf("maxBucketLen:%d\n", maxBucketLen);
			printf("averageBucketLen:%lf\n\n", averageBucketLen);
		}

	private:
		vector<Node*> _table;
		int _n;

	public:
		void TestHT1()
		{
			hash_table<int, int> ht;
			int a[] = { 4,14,24,34,5,7,1 };
			for (auto e : a)
			{
				ht.Insert(make_pair(e, e));
			}

			ht.Insert(make_pair(3, 3));
			ht.Insert(make_pair(3, 3));
			ht.Insert(make_pair(-3, -3));

			ht.Some();
		}

		void TestHT2()
		{
			string arr[] = { "香蕉", "甜瓜","苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
			//HashTable<string, int, HashFuncString> ht;
			hash_table<string, int> ht;
			for (auto& e : arr)
			{
				//auto ret = ht.Find(e);
				HashNode<string, int>* ret = ht.Find(e);
				if (ret)
				{
					ret->_kv.second++;
				}
				else
				{
					ht.Insert(make_pair(e, 1));
				}
			}

			ht.Insert(make_pair("apple", 1));
			ht.Insert(make_pair("sort", 1));

			ht.Insert(make_pair("abc", 1));
			ht.Insert(make_pair("acb", 1));
			ht.Insert(make_pair("aad", 1));
		}

		void TestHT3()
		{
			const size_t N = 1000;

			unordered_set<int> us;
			set<int> s;
			hash_table<int, int> ht;

			vector<int> v;
			v.reserve(N);
			srand(time(0));
			for (size_t i = 0; i < N; ++i)
			{
				//v.push_back(rand()); // N比较大时,重复值比较多
				v.push_back(rand() + i); // 重复值相对少
				//v.push_back(i); // 没有重复,有序
			}

			size_t begin1 = clock();
			for (auto e : v)
			{
				s.insert(e);
			}
			size_t end1 = clock();
			cout << "set insert:" << end1 - begin1 << endl;

			size_t begin2 = clock();
			for (auto e : v)
			{
				us.insert(e);
			}
			size_t end2 = clock();
			cout << "unordered_set insert:" << end2 - begin2 << endl;

			size_t begin3 = clock();
			for (auto e : v)
			{
				ht.Insert(make_pair(e, e));
			}
			size_t end3 = clock();
			cout << "hash_table insert:" << end3 - begin3 << endl << endl;


			size_t begin4 = clock();
			for (auto e : v)
			{
				s.find(e);
			}
			size_t end4 = clock();
			cout << "set find:" << end4 - begin4 << endl;

			size_t begin5 = clock();
			for (auto e : v)
			{
				us.find(e);
			}
			size_t end5 = clock();
			cout << "unordered_set find:" << end5 - begin5 << endl;

			size_t begin6 = clock();
			for (auto e : v)
			{
				ht.Find(e);
			}
			size_t end6 = clock();
			cout << "hash_table find:" << end6 - begin6 << endl << endl;

			cout << "插入数据个数:" << us.size() << endl << endl;
			ht.Some();

			size_t begin7 = clock();
			for (auto e : v)
			{
				s.erase(e);
			}
			size_t end7 = clock();
			cout << "set erase:" << end7 - begin7 << endl;

			size_t begin8 = clock();
			for (auto e : v)
			{
				us.erase(e);
			}
			size_t end8 = clock();
			cout << "unordered_set erase:" << end8 - begin8 << endl;

			size_t begin9 = clock();
			for (auto e : v)
			{
				ht.Erase(e);
			}
			size_t end9 = clock();
			cout << "hash_table Erase:" << end9 - begin9 << endl << endl;
		}
	};

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508

二、unordered_set的实现及测试

#pragma once

#include"HashTable.h"

namespace aj
{
	template<class K>
	class unordered_set
	{
	public:
		struct SetKeyOfT
		{
			const K& operator()(const K& k)
			{
				return k;
			}
		};

	public:
		// 因为unordered_set中K是不能被改变
		// 所以普通迭代器也无法改变K的值
		// 所以让普通迭代器也是const迭代器
		typedef typename hash_bucket::hash_table<const K, K, SetKeyOfT, HashFunc<K>>::const_iterator iterator;
		typedef typename hash_bucket::hash_table<const K, K, SetKeyOfT, HashFunc<K>>::const_iterator const_iterator;

		// 由于_ht.Insert(key)返回的普通迭代器
		// 而pair<iterator, bool>中的迭代器
		// 看起来是普通迭代器,但实际上是const迭代器
		// 所以这里不能直接 return _ht.Insert(key)
		pair<iterator, bool> insert(const K& key)
		{
			auto tmp = _ht.Insert(key);
			return make_pair(iterator(tmp.first._node, tmp.first._pht, tmp.first.hashi), tmp.second);
		}

		// 由于这里普通迭代器也是const迭代器
		// 那么这里只保留const迭代器版本
		/*iterator begin()
		{
			return _ht.begin();
		}

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

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

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

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

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

		void clear()
		{
			_ht.Clear();
		}

		size_t size()
		{
			return _ht.Size();
		}

		void swap(unordered_set<K>& us)
		{
			_ht.Swap(us._ht);
		}
	private:
		// unordered_set中K是不能被改变的
		hash_bucket::hash_table <const K, K , SetKeyOfT , HashFunc<K>> _ht;
	};

	void test_unordered_set()
	{
		// 17:05
		/*unordered_set<int> us;
		us.insert(5);
		us.insert(15);
		us.insert(52);
		us.insert(3);*/

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

		unordered_set<int> us1;
		us1.insert(1);
		us1.insert(2);
		us1.insert(3);
		us1.insert(4);


		unordered_set<int> us2;
		us2.insert(10);
		us2.insert(20);
		us2.insert(30);
		us2.insert(40);
		for (auto e : us1)
		{
			cout << e << " ";
		}
		cout << endl;

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

		us1.swap(us2);

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

		for (auto e : us2)
		{
			cout << e << " ";
		}
		cout << endl;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143

三、unordered_map的实现及测试

#pragma once

#include"HashTable.h"

namespace aj
{
	template<class K , class V>
	class unordered_map
	{
	public:
		struct MapKeyOfT
		{
			const K& operator()(const pair<K, V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename hash_bucket::hash_table<K, pair<const K, V>, MapKeyOfT, HashFunc<K>>::iterator iterator;
		typedef typename hash_bucket::hash_table<K, pair<const K, V>, MapKeyOfT, HashFunc<K>>::const_iterator const_iterator;

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

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

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

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

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

		V& operator[](const K& key)
		{
			auto tmp = _ht.Insert(make_pair(key,V()));
			return tmp.first->second;
		}

		const V& operator[](const K& key)const
		{
			auto tmp = _ht.Insert(make_pair(key, V()));
			return tmp.first->second;
		}

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

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

		void clear()
		{
			_ht.Clear();
		}

		size_t size()
		{
			return _ht.Size();
		}

		void swap(unordered_map<K,V>& um)
		{
			_ht.Swap(um._ht);
		}

	private:
		// unordered_map中K是不能被改变的
		hash_bucket::hash_table <K, pair<const K, V>, MapKeyOfT , HashFunc<K>> _ht;
	};
	void test_unordered_map1()
	{
		unordered_map<int, int> um;
		um.insert(make_pair(1, 1));
		um.insert(make_pair(2, 2));
		um.insert(make_pair(3, 3));
		um.insert(make_pair(4, 4));

		unordered_map<int, int>::iterator it = um.begin();
		while (it != um.end())
		{
			cout << it->first << ' ' << it->second << endl;
			++it;
		}
	}

	void test_unordered_map2()
	{
		unordered_map<string, string> dict;
		dict.insert(make_pair("sort", "排序"));
		dict.insert(make_pair("insert", "插入"));
		dict.insert(make_pair("string", "字符串"));


		for (auto& kv : dict)
		{
			// kv.first += 'x';
			kv.second += 'x';

			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;

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

		for (auto& kv : count_map)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

结尾

到目前已经将哈希的大部分内容讲述完了,那么下一篇文章将继续完善哈希,讲述位图和布隆过滤器。

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!! 本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】

推荐阅读
相关标签