【C++】哈希表的模拟实现及 unordered_set 和 unorderded_map 的封装

avatar
作者
猴君
阅读量:0

在这里插入图片描述

目录

前言

上一篇文章中讲到了哈希的概念和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.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 哈希表的模拟实现

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.2 哈希表中节点类的实现

namespace hash_bucket { 	template<class T> 	struct HashNode 	{ 		HashNode* _next; 		T _data;  		HashNode(const T& data) 			:_data(data) 			, _next(nullptr) 		{} 	};  } 

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.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.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.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.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.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.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; 		} 	};  } 

二、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; 	} } 

三、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; 	} } 

结尾

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

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!