A simple analog implementation of a hash table

Getting to Know Hash

Hash table is an algorithm with high search efficiency. In the best case, the time complexity of query is O(1).

unordered_mapContainers are faster by keyaccessing individual elements thanmap

lower.

underlying structure

unorderedThe reason why series of associative containers are more efficient is that the underlying layer uses a hash structure.

Hash is through keymapping, and then directly get the required data through the mapping value, which is more efficient. The search of the balanced tree is through sequential comparison, which is relatively slow.

  • Insert element : By calculating the mapping value of the element, the element is inserted into the storage position through the mapping value.
  • Search element : get the element by calculating the mapping value of the element.

The conversion function used in the hash method is called a hash (hash) function, and the constructed structure is called a hash table (hash table)

Example: set {1, 7, 6, 4, 5, 9, 11, 21};

The hash function is: hash(key)=key%capacity , and capacity is the maximum value of the underlying space.

0 1 2 3 4 5 6 7 8 9
1 11 21 4 5 6 9

1%10=1、4%10=4、7%10=10…

But what if I want to insert an 11?

This is a classic problem, hash collision

hash collision

Two common ways to resolve hash collisions are: closed hashing and open hashing .

closed hash

Closed hashing is also called open addressing method. When a conflict occurs, I will look for it later. If 1 and 11 go to %10, both are equal to 1, but 1 goes first to occupy the No. 1 pit, then 11 must not be able to use it. The pit position of 1 has been robbed, so we can only find out whether there are any occupied pit positions, and if so, put 11. This method is called linear detection method .

But what if I want to delete a value?

0 1 2 3 4 5 6 7 8 9
1 11 21 4 5 6 9

For example, this piece of data, after I delete 11

0 1 2 3 4 5 6 7 8 9
1 21 4 5 6 9

The position of 2 is vacant. When I want to find 21, I can’t find it, because finding a certain value is the same as inserting a certain value. First determine the mapping value. If it is not the current value, then look for it later. , if it is empty, the search is over, here 2 is empty, you can’t continue to search, you have to return to the search failure, but 21 exists, so you can mark each hash node, in each node Record a status value, whether it is Empty, Exit or Delete , so that the above situation can be avoided.

Define a hash node

	//枚举状态
	enum State
	{
    
    
		Empty,
		Exit,
		Delete
	};

	template<class K,class V>
	struct Hash_Node
	{
    
    
		pair<K, V> _kv;
		State _state = Empty;
	};

Define a hash table

	template<class K,class V>
	class Hash_table
	{
    
    
	public:
		typedef Hash_Node<K, V> Node;
		
	private:
		vector<Node> _tables;
		size_t _size=0;
	};

Under what circumstances should the hash table be expanded? How to expand?

Insert() function

bool Insert(const pair<K,V>& key)
		{
    
    
			//查重
			if (Find(key.first))
			{
    
    
				return false;
			}
			//扩容

			if (_tables.size()==0||10*_size / _tables.size()>=7)
			{
    
    
				//大于7需要扩容
				size_t newSize = _tables.size() == 0 ? 10 : 2 * _tables.size();
				Hash_table<K, V>newHT;
				newHT._tables.resize(newSize);//新表

				//复用Insert函数
				for (auto& e : _tables)
				{
    
    
					if (e._state == Exit)
					{
    
    
						newHT.Insert(e._kv);
					}
				}
				_tables.swap(newHT._tables);
			}
    			//线性探测
			size_t hashi = key.first % _tables.size();
			while (_tables[hashi]._state == Exit)
			{
    
    
				hashi++;
				hashi %= _tables.size();
			}
			_tables[hashi]._kv = key;
			_tables[hashi]._state = Exit;
			_size++;
    		return true;
		}

Find() function

Hash_Node<K, V>* Find(const K& key)
		{
    
    
			if (_tables.size() == 0) return nullptr;

			size_t start = key % _tables.size();
			size_t begin = start;
			while (_tables[start]._state != Empty)
			{
    
    
				if (_tables[start]._state != Delete && _tables[start]._kv.first == key)
				{
    
    
					return &_tables[start];
				}
				start++;
				start %= _tables.size();

				if (begin == start)
				{
    
    
					break;
				}
			}
			return nullptr;
		}

sample test

	void test1()
	{
    
    
		int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10,11,12,21,31,41,51,61,71,81,91,101 };
		Hash_table<int, int>hs;
		for (auto e : arr)
		{
    
    
			hs.Insert(make_pair(e, e));
		}
	}

The test results are as follows:

It can be seen that all have been inserted successfully.

The priority of linear detection: simple and convenient.

Disadvantages of linear detection: Once a hash conflict occurs, all conflicts will accumulate together, which will cause the search efficiency to become very low.

secondary detection

The secondary detection is actually ithe square interval that is skipped each time, and the original linear detection is to search backward one by one.

0 1 2 3 4 5 6 7 8 9
Exit Exit Exit

For example, if a hash collision occurs at 1, then the linear detection will look for the 2 position, and then find the 3 position until it finds an empty space.

But the second detection is 1 or not, i=1, the square of i is equal to 1, find the 2 position, i=2, the square of i is equal to 4, find the 5 position, and find that there is no element, just occupy the place directly, the second detection can make Data is more dispersed, reducing the incidence of hash collisions.

		size_t start = hash(kv.first) % _tables.size();
		size_t i = 0;
		size_t hashi = start;
		// 二次探测
		while (_tables[hashi]._state == Exit)
		{
    
    
			++i;
			hashi = start + i*i;
			hashi %= _tables.size();
		}

		_tables[hashi]._kv = kv;
		_tables[hashi]._state = EXIST;
		++_size;

The above hash table can only be used to map the value of int type. If it is other types, it will not work. Here you can add a functor to be compatible with other types. The most important thing here is the type. How can the type be converted into a stringvalue string? .

We can add the ASCII codes to get the key, but there will be a hash collision in the following scenarios.

string str1="abc";
string str2="acb";
string str3="cba";

Someone here came to a conclusion

hash = hash * 131 + ch, which can reduce the probability of hash collision.

HashFunc() functor

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

	//特例化模板参数来解决string的问题
	template<>
	struct HashFunc<string>
	{
    
    
		size_t operator()(const string& key)
		{
    
    
			size_t val = 0;
			for (auto ch : key)
			{
    
    
				val *= 131;
				val += ch;
			}

			return val;
		}
	};
#pragma once
#include<iostream>
#include<set>
#include<vector>
using namespace std;

//闭散列
namespace mudan
{
    
    
	template<class K>
	struct HashFunc
	{
    
    
		size_t operator()(const K& key)
		{
    
    
			return (size_t)key;
		}
	};

	//特例化模板参数来解决string的问题
	template<>
	struct HashFunc<string>
	{
    
    
		size_t operator()(const string& key)
		{
    
    
			size_t val = 0;
			for (auto ch : key)
			{
    
    
				val *= 131;
				val += ch;
			}

			return val;
		}
	};

	enum State
	{
    
    
		Empty,
		Exit,
		Delete
	};

	template<class K,class V>
	struct Hash_Node
	{
    
    
		pair<K, V> _kv;
		State _state = Empty;
	};

	template<class K,class V,class Hash=HashFunc<K>>
	class Hash_table
	{
    
    
	public:
		typedef Hash_Node<K, V> Node;
		
		bool Insert(const pair<K,V>& key)
		{
    
    
			//查重
			if (Find(key.first))
			{
    
    
				return false;
			}
			//扩容

			if (_tables.size()==0||10*_size / _tables.size()>=7)
			{
    
    
				//大于7需要扩容
				size_t newSize = _tables.size() == 0 ? 10 : 2 * _tables.size();
				Hash_table<K, V>newHT;
				newHT._tables.resize(newSize);//新表

				//复用Insert函数
				for (auto &e : _tables)
				{
    
    
					if (e._state == Exit)
					{
    
    
						newHT.Insert(e._kv);
					}
				}
				_tables.swap(newHT._tables);
			}
			
			Hash hash;
			//线性探测
			size_t hashi = hash(key.first) % _tables.size();
			while (_tables[hashi]._state == Exit)
			{
    
    
				hashi++;
				hashi %= _tables.size();
			}
			_tables[hashi]._kv = key;
			_tables[hashi]._state = Exit;
			_size++;
            return true;
		}

		Hash_Node<K, V>* Find(const K& key)
		{
    
    
			if (_tables.size() == 0) return nullptr;

			Hash hash;
			size_t start = hash(key) % _tables.size();
			size_t begin = start;
			while (_tables[start]._state != Empty)
			{
    
    
				if (_tables[start]._state != Delete && _tables[start]._kv.first == key)
				{
    
    
					return &_tables[start];
				}
				start++;
				start %= _tables.size();

				if (begin == start)
				{
    
    
					break;
				}
			}
			return nullptr;
		}

	private:
		vector<Node> _tables;
		size_t _size;
	};

	void TestHT2()
	{
    
    
		string arr[] = {
    
     "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

		//HashTable<string, int, HashFuncString> countHT;
		Hash_table<string, int> countHT;
		for (auto& str : arr)
		{
    
    
			auto ptr = countHT.Find(str);
			if (ptr)
			{
    
    
				ptr->_kv.second++;
			}
			else
			{
    
    
				countHT.Insert(make_pair(str, 1));
			}
		}
	}


	void test1()
	{
    
    
		int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10,11,12,21,31,41,51,61,71,81,91,101 };
		Hash_table<int, int>hs;
		for (auto e : arr)
		{
    
    
			hs.Insert(make_pair(e, e));
		}
	}
}

It can be seen that the mapping is also successful.

The problem mentioned before has also been solved.

string str1="abc";
string str2="acb";
string str3="cba";		

Erase() function

This is simple. Erase does not delete the number from the array in the true sense, but changes the state, changing the state to Delete.

		bool Erase(const K& key)
		{
    
    
			Hash_Node<K, V>* ret = Find(key);
			if (ret)
			{
    
    
				ret->_state = Delete;
				--_size;
				return true;
			}
			else
			{
    
    
				return false;
			}
		}

full code

#pragma once
#include<iostream>
#include<set>
#include<vector>
using namespace std;

//闭散列
namespace mudan
{
    
    
	template<class K>
	struct HashFunc
	{
    
    
		size_t operator()(const K& key)
		{
    
    
			return (size_t)key;
		}
	};

	//特例化模板参数来解决string的问题
	template<>
	struct HashFunc<string>
	{
    
    
		size_t operator()(const string& key)
		{
    
    
			size_t val = 0;
			for (auto ch : key)
			{
    
    
				val *= 131;
				val += ch;
			}

			return val;
		}
	};

	enum State
	{
    
    
		Empty,
		Exit,
		Delete
	};

	template<class K,class V>
	struct Hash_Node
	{
    
    
		pair<K, V> _kv;
		State _state = Empty;
	};

	template<class K,class V,class Hash=HashFunc<K>>
	class Hash_table
	{
    
    
	public:
		typedef Hash_Node<K, V> Node;
		
		bool Insert(const pair<K,V>& key)
		{
    
    
			//查重
			if (Find(key.first))
			{
    
    
				return false;
			}
			//扩容

			if (_tables.size()==0||10*_size / _tables.size()>=7)
			{
    
    
				//大于7需要扩容
				size_t newSize = _tables.size() == 0 ? 10 : 2 * _tables.size();
				Hash_table<K, V>newHT;
				newHT._tables.resize(newSize);//新表

				//复用Insert函数
				for (auto &e : _tables)
				{
    
    
					if (e._state == Exit)
					{
    
    
						newHT.Insert(e._kv);
					}
				}
				_tables.swap(newHT._tables);
			}
			
			Hash hash;
			//线性探测
			size_t hashi = hash(key.first) % _tables.size();
			while (_tables[hashi]._state == Exit)
			{
    
    
				hashi++;
				hashi %= _tables.size();
			}
			_tables[hashi]._kv = key;
			_tables[hashi]._state = Exit;
			_size++;
			return true;
		}

		Hash_Node<K, V>* Find(const K& key)
		{
    
    
			if (_tables.size() == 0) return nullptr;

			Hash hash;
			size_t start = hash(key) % _tables.size();
			size_t begin = start;
			while (_tables[start]._state != Empty)
			{
    
    
				if (_tables[start]._state != Delete && _tables[start]._kv.first == key)
				{
    
    
					return &_tables[start];
				}
				start++;
				start %= _tables.size();

				if (begin == start)
				{
    
    
					break;
				}
			}
			return nullptr;
		}

		bool Erase(const K& key)
		{
    
    
			Hash_Node<K, V>* ret = Find(key);
			if (ret)
			{
    
    
				ret->_state = Delete;
				--_size;
				return true;
			}
			else
			{
    
    
				return false;
			}
		}

	private:
		vector<Node> _tables;
		size_t _size=0;
	};

	void TestHT2()
	{
    
    
		string arr[] = {
    
     "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

		//HashTable<string, int, HashFuncString> countHT;
		Hash_table<string, int> countHT;
		for (auto& str : arr)
		{
    
    
			auto ptr = countHT.Find(str);
			if (ptr)
			{
    
    
				ptr->_kv.second++;
			}
			else
			{
    
    
				countHT.Insert(make_pair(str, 1));
			}
		}
	}


	void test1()
	{
    
    
		int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10,11,12,21,31,41,51,61,71,81,91,101 };
		Hash_table<int, int>hs;
		for (auto e : arr)
		{
    
    
			hs.Insert(make_pair(e, e));
		}
	}

	void TestHT3()
	{
    
    
		HashFunc<string> hash;
		cout << hash("abcd") << endl;
		cout << hash("bcad") << endl;
		cout << hash("eat") << endl;
		cout << hash("ate") << endl;
		cout << hash("abcd") << endl;
		cout << hash("aadd") << endl << endl;

		cout << hash("abcd") << endl;
		cout << hash("bcad") << endl;
		cout << hash("eat") << endl;
		cout << hash("ate") << endl;
		cout << hash("abcd") << endl;
		cout << hash("aadd") << endl << endl;
	}
}

open hash

Open hashing is shown in the above figure. It has a bucket to represent the key value, and then all the keys with the same key value (hash conflicts) are connected to the position corresponding to the key of this bucket.

This bucket is actually an array of pointers .

Define a hash node

	template<class K,class V>
	struct HashNode
	{
    
    
		pair<K, V> _kv;
		HashNode<K,V>* _next;

		HashNode(const pair<K,V>& data)
			:_kv(data)
			,_next(nullptr)
		{
    
    }
	};

Define a hash table

template<class K, class V, class Hash = HashFunc<K>>
	class HashTable
	{
    
    
		typedef HashNode<K, V> Node;

	public:

	private:
		vector<Node*>_tables;
		size_t _size=0;
	};

Insert() function

Both the head insertion and the tail insertion of the insertion operation are very fast. Here, since the single linked list is defined, the head insertion is selected.

The insertion process is shown in the figure below:

bool Insert(const pair<K, V>& key)
		{
    
    
			Hash hash;
			//去重

			if (Find(key.first)) return false;

			//负载因子等于1就要扩容了

			if (_size == _tables.size())
			{
    
    
				size_t newsize = _tables.size() == 0 ? 10:2 * _tables.size();
				vector<Node*>newTables;
				newTables.resize(newsize);
				
				for (int i = 0; i < _tables.size(); i++)
				{
    
    
					Node* cur = _tables[i];
					while (cur)
					{
    
    
						Node* next = cur->_next;
						
						size_t hashi = hash(cur->_kv.first) % newTables.size();
						cur->_next =newTables[hashi];
						newTables[hashi] = cur;
						cur = next;
					}
					_tables[i] = nullptr;//销毁原来的桶
				}
				_tables.swap(newTables);
			}

			//头插
			//  head
			//    1     2头插,2->next=1,head=2;
			size_t hashi = hash(key.first) % _tables.size();
			Node* newnode = new Node(key);
			newnode->_next = _tables[hashi];
			_tables[hashi] = newnode;
			++_size;

			return true;
		}

Find() function

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

			Hash hash;
			size_t hashi = hash(key) % _tables.size();
			Node* cur = _tables[hashi];
			while (cur)
			{
    
    
				if (cur->_kv.first == key)
				{
    
    
					return cur;
				}
				cur = cur->_next;
			}
			//没找到,返回空
			return nullptr;
		}

Erase() function

It is exactly the same as the delete of the linked list

bool Erase(const K& key)
		{
    
    
			if (_tables.size() == 0)
			{
    
    
				return nullptr;
			}

			Hash hash;
			size_t hashi = hash(key) % _tables.size();
			Node* prev = nullptr;
			Node* cur = _tables[hashi];
			while (cur)
			{
    
    
				if (cur->_kv.first == key)
				{
    
    
					// 1、头删
					// 2、中间删
					if (prev == nullptr)
					{
    
    
						_tables[hashi] = cur->_next;
					}
					else
					{
    
    
						prev->_next = cur->_next;
					}

					delete cur;
					--_size;

					return true;
				}

				prev = cur;
				cur = cur->_next;
			}

			return false;
		}

total code

#pragma once
#include<iostream>
#include<set>
#include<vector>
using namespace std;

//闭散列
namespace mudan
{
    
    
	template<class K>
	struct HashFunc
	{
    
    
		size_t operator()(const K& key)
		{
    
    
			return (size_t)key;
		}
	};

	//特例化模板参数来解决string的问题
	template<>
	struct HashFunc<string>
	{
    
    
		size_t operator()(const string& key)
		{
    
    
			size_t val = 0;
			for (auto ch : key)
			{
    
    
				val *= 131;
				val += ch;
			}

			return val;
		}
	};

	enum State
	{
    
    
		Empty,
		Exit,
		Delete
	};

	template<class K,class V>
	struct Hash_Node
	{
    
    
		pair<K, V> _kv;
		State _state = Empty;
	};

	template<class K,class V,class Hash=HashFunc<K>>
	class Hash_table
	{
    
    
	public:
		typedef Hash_Node<K, V> Node;
		
		bool Insert(const pair<K,V>& key)
		{
    
    
			//查重
			if (Find(key.first))
			{
    
    
				return false;
			}
			//扩容

			if (_tables.size()==0||10*_size / _tables.size()>=7)
			{
    
    
				//大于7需要扩容
				size_t newSize = _tables.size() == 0 ? 10 : 2 * _tables.size();
				Hash_table<K, V>newHT;
				newHT._tables.resize(newSize);//新表

				//复用Insert函数
				for (auto &e : _tables)
				{
    
    
					if (e._state == Exit)
					{
    
    
						newHT.Insert(e._kv);
					}
				}
				_tables.swap(newHT._tables);
			}
			
			Hash hash;
			//线性探测
			size_t hashi = hash(key.first) % _tables.size();
			while (_tables[hashi]._state == Exit)
			{
    
    
				hashi++;
				hashi %= _tables.size();
			}
			_tables[hashi]._kv = key;
			_tables[hashi]._state = Exit;
			_size++;
			return true;
		}

		Hash_Node<K, V>* Find(const K& key)
		{
    
    
			if (_tables.size() == 0) return nullptr;

			Hash hash;
			size_t start = hash(key) % _tables.size();
			size_t begin = start;
			while (_tables[start]._state != Empty)
			{
    
    
				if (_tables[start]._state != Delete && _tables[start]._kv.first == key)
				{
    
    
					return &_tables[start];
				}
				start++;
				start %= _tables.size();

				if (begin == start)
				{
    
    
					break;
				}
			}
			return nullptr;
		}

		bool Erase(const K& key)
		{
    
    
			Hash_Node<K, V>* ret = Find(key);
			if (ret)
			{
    
    
				ret->_state = Delete;
				--_size;
				return true;
			}
			else
			{
    
    
				return false;
			}
		}

	private:
		vector<Node> _tables;
		size_t _size=0;
	};

	void TestHT2()
	{
    
    
		string arr[] = {
    
     "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };

		//HashTable<string, int, HashFuncString> countHT;
		Hash_table<string, int> countHT;
		for (auto& str : arr)
		{
    
    
			auto ptr = countHT.Find(str);
			if (ptr)
			{
    
    
				ptr->_kv.second++;
			}
			else
			{
    
    
				countHT.Insert(make_pair(str, 1));
			}
		}
	}


	void test1()
	{
    
    
		int arr[] = {
    
     1,2,3,4,5,6,7,8,9,10,11,12,21,31,41,51,61,71,81,91,101 };
		Hash_table<int, int>hs;
		for (auto e : arr)
		{
    
    
			hs.Insert(make_pair(e, e));
		}
	}

	void TestHT3()
	{
    
    
		HashFunc<string> hash;
		cout << hash("abcd") << endl;
		cout << hash("bcad") << endl;
		cout << hash("eat") << endl;
		cout << hash("ate") << endl;
		cout << hash("abcd") << endl;
		cout << hash("aadd") << endl << endl;

		cout << hash("abcd") << endl;
		cout << hash("bcad") << endl;
		cout << hash("eat") << endl;
		cout << hash("ate") << endl;
		cout << hash("abcd") << endl;
		cout << hash("aadd") << endl << endl;
	}
}

namespace mudan1
{
    
    

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

	//特例化模板参数来解决string的问题
	template<>
	struct HashFunc<string>
	{
    
    
		size_t operator()(const string& key)
		{
    
    
			size_t val = 0;
			for (auto ch : key)
			{
    
    
				val *= 131;
				val += ch;
			}

			return val;
		}
	};

	template<class K,class V>
	struct HashNode
	{
    
    
		pair<K, V> _kv;
		HashNode<K,V>* _next;

		HashNode(const pair<K,V>& data)
			:_kv(data)
			,_next(nullptr)
		{
    
    }
	};

	template<class K, class V, class Hash = HashFunc<K>>
	class HashTable
	{
    
    
		typedef HashNode<K, V> Node;

	public:

		bool Insert(const pair<K, V>& key)
		{
    
    
			Hash hash;
			//去重

			if (Find(key.first)) return false;

			//负载因子等于1就要扩容了

			if (_size == _tables.size())
			{
    
    
				size_t newsize = _tables.size() == 0 ? 10:2 * _tables.size();
				vector<Node*>newTables;
				newTables.resize(newsize);
				
				for (int i = 0; i < _tables.size(); i++)
				{
    
    
					Node* cur = _tables[i];
					while (cur)
					{
    
    
						Node* next = cur->_next;
						
						size_t hashi = hash(cur->_kv.first) % newTables.size();
						cur->_next =newTables[hashi];
						newTables[hashi] = cur;
						cur = next;
					}
					_tables[i] = nullptr;//销毁原来的桶
				}
				_tables.swap(newTables);
			}

			//头插
			//  head
			//    1     2头插,2->next=1,head=2;
			size_t hashi = hash(key.first) % _tables.size();
			Node* newnode = new Node(key);
			newnode->_next = _tables[hashi];
			_tables[hashi] = newnode;
			++_size;

			return true;
		}

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

			Hash hash;
			size_t hashi = hash(key) % _tables.size();
			Node* cur = _tables[hashi];
			while (cur)
			{
    
    
				if (cur->_kv.first == key)
				{
    
    
					return cur;
				}
				cur = cur->_next;
			}
			//没找到,返回空
			return nullptr;
		}

		bool Erase(const K& key)
		{
    
    
			if (_tables.size() == 0)
			{
    
    
				return nullptr;
			}

			Hash hash;
			size_t hashi = hash(key) % _tables.size();
			Node* prev = nullptr;
			Node* cur = _tables[hashi];
			while (cur)
			{
    
    
				if (cur->_kv.first == key)
				{
    
    
					// 1、头删
					// 2、中间删
					if (prev == nullptr)
					{
    
    
						_tables[hashi] = cur->_next;
					}
					else
					{
    
    
						prev->_next = cur->_next;
					}

					delete cur;
					--_size;

					return true;
				}

				prev = cur;
				cur = cur->_next;
			}

			return false;
		}

	private:
		vector<Node*>_tables;
		size_t _size=0;
	};

	void TestHT1()
	{
    
    
		int a[] = {
    
     1, 11, 4, 15, 26, 7, 44,55,99,78 };
		HashTable<int, int> ht;
		for (auto e : a)
		{
    
    
			ht.Insert(make_pair(e, e));
		}

		ht.Insert(make_pair(22, 22));
	}
}

Guess you like

Origin blog.csdn.net/AkieMo/article/details/131968980