C++--哈希表的实现及unorder_set和unorder_map的封装

这篇具有很好参考价值的文章主要介绍了C++--哈希表的实现及unorder_set和unorder_map的封装。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.什么是哈希表

哈希表是一种数据结构,用来存放数据的,哈希表存放的数据是无序的,可以实现增删查,当时不能修改数据。可以不经过任何比较,一次直接从表中得到要搜索的元素。如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)。
unordered_map是存储<key, value>键值对的关联式容器,其允许通过keys快速的索引到与其对应的value。
在unordered_map中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
在内部,unordered_map没有对<kye, value>按照任何特定的顺序排序, 为了能在常数范围内找到key所对应的value,unordered_map将相同哈希值的键值对放在相同的桶中。
unordered_map容器通过key访问单个元素要比map快,但它通常在遍历元素子集的范围迭代方面效率较低。
unordered_maps实现了直接访问操作符(operator[]),它允许使用key作为参数直接访问value。
它的迭代器至少是前向迭代器。

unorder_set是用来存储<key>的关联式容器,可以用来快速的查找和去重,在内部是按照无序的方式排列的,它的迭代器和unorder_map的使用相同,其他的特性和unorder_map的特性差不多。

2.哈希冲突

对于两个数据元素的关键字$k_i$和 $k_j$(i != j),有$k_i$ != $k_j$,但有:Hash($k_i$) ==
Hash($k_j$),即:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。

解决哈希冲突:

引起哈希冲突的一个原因可能是:哈希函数设计不够合理。
哈希函数设计原则:
哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值
域必须在0到m-1之间;哈希函数计算出来的地址能均匀分布在整个空间中;哈希函数应该比较简单。

解决哈希冲突两种常见的方法是:闭散列和开散列

闭散列:

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

通过哈希函数获取待插入元素在哈希表中的位置,如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素。

开散列:

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地
址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链
接起来,各链表的头结点存储在哈希表中。

开散列与闭散列比较:
应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上:
由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装载因子a <=
0.7,而表项所占空间又比指针大的多,所以使用链地址法反而比开地址法节省存储空间。

3.哈希表的实现

闭散列的实现:

#include <iostream>
#include <vector>
#include <string>
//usng namespace std;
using std::cout;
using std:: endl;
using std::cin;
//闭散列
namespace open_address
{
 //处理不是整形的字符
	template<class T>
	struct DefaultHashFunc
	{
		size_t operator()(const T& t)
		{
			return size_t(value(t));

		}
	};
 //特殊化处理字符串
	template<>
	struct DefaultHashFunc<string>
	{
		const size_t operator()(const string& t)
		{
			//KeyofT value;
			size_t num=1;
			for (auto e : t)
			{
				num *= 131;
				num +=e;
			}
			return num;

		}
	};
 //枚举三种状态
	enum State
	{
		Empty,
		Exist,
		Delete
	};
 //哈希节点
	template<class T>
	struct HashDateNode
	{
	private:
		T _kv;
		State _state=Empty;
	};
//哈希表
	template<class K, class T,class KeyofT,class DefaultHashFunc>
	class HashTable
	{
		typedef HashDateNode<T> Node;
		HashTable()//初始化,开辟10个空间
		{
			_Date.resize(10);
		}
		//插入数值
		bool insert(const T& Date)
		{

			DefaultHashFunc Func;//处理字符串问题
			KeyofT value;//处理set和map的数值问题函数
			//扩容
			if (n * 10 > _Date.size() * 7)//负载因子
			{
				int newsize = _Date.size() * 2;
				vector<Node*> newHT;
				newHT.resize(newsize);//开辟空间
				for (int i = 0; i < _Date.size(); i++)
				{
					if (_Date._state == Exist)//讲旧数据写入新空间中
					{
						newHT.insert(KetofT(_Date));
					}
					_Date.swap(newHT._Date);//交换数据
				}
			}
			//插入哈希表
			size_t hashi =Func(value(Date))% _Date.size();
			while (_Date[hashi]._state == Exist)//存在就++
			{
				++hashi;
				hashi %= _Date.size();
			}
			_Date[hashi]._kv = Date;
			_Date[hashi]._state = Exist;
			n++;//存放个数加一
			return true;
		}
		//查找函数
		vector<Node*> Find(const K& t)
		{
			
			DefaultHashFunc Func;
			KeyofT value;
			size_t hashi = Func(value(t)) % _Date.size();
			while (_Date[hashi]._state != Empty)
			{
				if (_Date[hashi]._state == Exist
					&& value(_Date[hashi]) == t)
				{
					return   _Date[hashi];
				}

				++hashi;
				hashi %= _Date.size();
			}

			return nullptr;

		}
 //删除
		bool erash(const K& key)
		{
			
			vector<Node*> ret = Find(key);//查找是否存在
			if (ret)
			{
				ret._state= Exist;
				n--;
				return true;
			}
			return false;
		}

	private:
		vector<Node*> _Date;//数据
		size_t n;//存储有效个数
	};
}

开散列的实现

#include <iostream>
#include <string>
#include <vector>
using namespace std;
//处理字符
template<class T>
struct DefaultHashFunc
{
	size_t operator()(const T& t)
	{
		return size_t(t);
	}
};template<>
struct DefaultHashFunc<string>
{
	size_t operator()(const string& t)
	{
		size_t num = 0;
		for (auto e : t)
		{
			num *= 131;
			num += e;
		}
		return num;
	}
};
//哈希桶,闭散列
namespace hash_bucket
{
	template<class T> 
	struct HashDateNode
	{
		T _Date;
		HashDateNode<T>* _next;

		HashDateNode(const T& Date)
			:_Date(Date)
			,_next(nullptr)
		{}
	};
	
	template<class K, class T, class KeyofT, class HashFunc>
	class HashDate;//前置声明

	//迭代器
	//template<class K,class T,class KeyofT ,class HashFunc>//旧版
	template<class K, class T, class Ptr, class Ref, class KeyofT, class HashFunc>//新版
	struct HashIterator
	{
		typedef HashDateNode<T> Node;
		
		typedef HashIterator<K,T, Ptr, Ref,KeyofT, HashFunc> Self;
		typedef HashIterator<K, T, T*, T&, KeyofT, HashFunc> iterator;

		Node* _node;
		const HashDate<K, T, KeyofT, HashFunc>* _pht; //设置位const ,防止普通类型无法转化为const类型

		//初始化
		/*const HashIterator(Node* node, HashDate<K, T, KeyofT, HashFunc>* pht)
			:_node(node)
			, _pht(pht)
		{}*/

		//const初始化
		HashIterator(Node* node, const HashDate<K, T, KeyofT, HashFunc>*  pht)
			:_node(node)
			, _pht(pht)
		{}


		// 普通迭代器时,他是拷贝构造
		// const迭代器时,他是构造函数
		HashIterator(const iterator& it)//防止set类型的const类型与非const类型的转换(模板不同)
			:_node(it._node)
			, _pht(it._pht)
		{}


		Ref operator*()
		{
			return _node->_Date;
		}
		Ptr operator->()
		{
			return &_node->_Date;
		}
		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
			{
				HashFunc Func;
				KeyofT value;
				size_t hashi = Func(value(_node->_Date)) % _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;
		}

	};

	template<class K, class T, class KeyofT, class HashFunc = DefaultHashFunc<K>>
	class HashDate
	{
		typedef HashDateNode<T> Node;
		
		// 
		//友元
		template<class K, class T, class Ptr, class Ref, class KeyofT, class HashFunc>
		friend struct HashIterator;//可以使用迭代器

	public:
		typedef HashIterator<K, T, T*, T&, KeyofT, HashFunc> iterator;
		typedef HashIterator<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);
		}

		const_iterator begin() const
		{
			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 end() const
		{
			return iterator(nullptr, this);
		}
		HashDate()
		{
			_table.resize(10, nullptr);
		}

		~HashDate()
		{
			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& date)
		{
			
			KeyofT value;
			HashFunc Func;
			iterator it = Find(value(date));
			//it!=end()
			if(it != end())
			{
				return make_pair(it,false);
			}

			if (n == _table.size())//扩容
			{
				int newsize = _table.size() * 2;
				vector<Node*> newHash;
				newHash.resize(newsize);
				for (size_t i = 0; i < _table.size(); i++)//旧数据
				{
					Node* cur = _table[i];
					while (cur)
					{
						Node* next = cur->_next;
						size_t hashi = Func(value(cur->_Date))% newsize;
						cur->_next = newHash[hashi];
						newHash[hashi] = cur;
						cur = next;
					}
					_table[i] = nullptr;
				}
				_table.swap(newHash);//交换数据
			}
			//插入
			size_t hashi = Func(value(date))% _table.size();//改变
			//Node* cur = _table[hashi];
			//尾插
			//Node* newNode = new Node(date);
			//while (cur)
			//{
			//	cur = cur->_next;
			//}
			//cur = newNode;
			//头插
			Node* newNode = new Node(date);//新节点
			newNode->_next = _table[hashi];//头结点
			_table[hashi] = newNode;//尾节点
		
			n++;
			return make_pair(iterator(newNode,this),true);
		}


		//查找
		iterator Find(const K& key)//Find为K类型的只用一个数值,T类型的在map中为pair<K,T>类型
		{
			HashFunc Func;
			KeyofT value;
			size_t hashi = Func(key) % _table.size();
			//size_t hashi = Func(value(key)) % _table.size();//不能使用这个
			Node* cur = _table[hashi];
			while (cur)
			{
				if (value(cur->_Date) == key)//?
				{
					return iterator(cur,this);
				}
				cur = cur->_next;
			}
			return iterator(nullptr,this);
		}

		//删除
		bool Erase(const K& key)
		{
			HashFunc Func;
			KeyofT value;
			iterator ret=Find(key);
			if (ret == end())
				return true;
			size_t x = Func(value(key))% _table.size();
			Node* cur = _table[x];
			Node* prev = nullptr;
			while (cur)
			{
				if (value(cur->_Date) == key)
				{
					if (prev == nullptr)
					{
						_table[x] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					
				}
				prev = cur;
				cur = cur->_next;
				delete cur;
				return true;
			}
			return false;
		}
		//打印
		void Print()
		{
			for (int i = 10; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				while (cur)
				{
					std::cout << cur->_Date.first<<" " << cur->_Date.second <<" " << std::endl;
					cur = cur->_next;
				}
			}
			std::cout << std::endl;
		}

	private:
		vector<Node*> _table; //存储数据
		size_t n=0; //记录容器中的个数
	};
}

4.Unorderset和Unordermap的实现

4.1 Unorderset

#pragma once
#include "HashTable.h"
using namespace hash_bucket;
//using namespace open_address;


template<class K>
class Unorderset
{
	struct SetKeyofT
	{
		const K& operator()(const K& k)
		{
			return k;
		}
	};
public:
	typedef typename hash_bucket::HashDate<K, K, SetKeyofT>::const_iterator iterator;
	typedef typename hash_bucket::HashDate<K, K, SetKeyofT>::const_iterator const_iterator;

	//typedef typename hash_bucket::HashDate<K, K, SetKeyofT> Hash;
public:
	const_iterator begin() const
	{
		return _ht.begin();
	}
	const_iterator end() const
	{
		return _ht.end();
	}
	pair<iterator, bool> insert(const K& k)
	{
		return _ht.Insert(k);
	}
	iterator find(const K& kk)
	{
		return _ht.Find(kk);
	}
	bool erase(const K& kk)
	{
		return _ht.Erase(kk);
	}
private:
	HashDate<K, K, SetKeyofT> _ht;
};

4.2 Unordermap

#pragma once
#include "HashTable.h"
using namespace hash_bucket;
template<class K,class T>
class Unordermap
{
	struct MapkeyofT
	{
		const K& operator()(const pair<const K, T>& kt)
		{
			return kt.first;
		}
	};
public:
	typedef typename hash_bucket::HashDate<K, pair<const K, T>, MapkeyofT>::iterator iterator;//普通迭代器
	typedef typename hash_bucket::HashDate<K, pair<const K, T>, MapkeyofT>::const_iterator const_iterator;//const迭代器
	//typedef typename hash_bucket::HashDate<K, pair<K, T>, MapkeyofT> Hash;
	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,T>& kt)
	{
		return _ht.Insert(kt);
	}
	//查找
	iterator find(const K& kk)
	{
		return _ht.Find(kk);
	}
	//重载[]
	T& operator[](const K& kk)
	{
		pair<iterator, bool> ret = insert(make_pair(kk, T()));
		return ret.first->second;
	}
	//删除
	bool eraser(const K& kk)
	{
		return _ht.Erase(kk);
	}
private:
	HashDate<K, pair<const K, T>, MapkeyofT> _ht;
};

4.3 完整代码

Ps:具体实现中建议分开写文章来源地址https://www.toymoban.com/news/detail-726262.html

#pragma once
#include "HashTable.h"
using namespace hash_bucket;
using namespace open_address;

//set实现
template<class K>
class Unorderset
{
	struct SetKeyofT
	{
		const K& operator()(const K& k)
		{
			return k;
		}
	};
public:
	typedef typename hash_bucket::HashDate<K, K, SetKeyofT>::const_iterator iterator;
	typedef typename hash_bucket::HashDate<K, K, SetKeyofT>::const_iterator const_iterator;

	//typedef typename hash_bucket::HashDate<K, K, SetKeyofT> Hash;
public:
	const_iterator begin() const
	{
		return _ht.begin();
	}
	const_iterator end() const
	{
		return _ht.end();
	}
	pair<iterator, bool> insert(const K& k)
	{
		return _ht.Insert(k);
	}
	iterator find(const K& kk)
	{
		return _ht.Find(kk);
	}
	bool erase(const K& kk)
	{
		return _ht.Erase(kk);
	}
private:
	HashDate<K, K, SetKeyofT> _ht;
};

//map实现
template<class K,class T>
class Unordermap
{
	struct MapkeyofT
	{
		const K& operator()(const pair<const K, T>& kt)
		{
			return kt.first;
		}
	};
public:
	typedef typename hash_bucket::HashDate<K, pair<const K, T>, MapkeyofT>::iterator iterator;//普通迭代器
	typedef typename hash_bucket::HashDate<K, pair<const K, T>, MapkeyofT>::const_iterator const_iterator;//const迭代器
	//typedef typename hash_bucket::HashDate<K, pair<K, T>, MapkeyofT> Hash;
	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,T>& kt)
	{
		return _ht.Insert(kt);
	}
	//查找
	iterator find(const K& kk)
	{
		return _ht.Find(kk);
	}
	//重载[]
	T& operator[](const K& kk)
	{
		pair<iterator, bool> ret = insert(make_pair(kk, T()));
		return ret.first->second;
	}
	//删除
	bool eraser(const K& kk)
	{
		return _ht.Erase(kk);
	}
private:
	HashDate<K, pair<const K, T>, MapkeyofT> _ht;
};
//底层实现
#pragma once//防止头文件重复引用
#include <iostream>
#include <vector>
#include <string>
using namespace std;


 //处理不是整形的字符
	template<class T>
	struct DefaultHashFunc
	{
		size_t operator()(const T& t)
		{
			return size_t(value(t));

		}
	};
 //特殊化处理字符串
	template<>
	struct DefaultHashFunc<string>
	{
		const size_t operator()(const string& t)
		{
			//KeyofT value;
			size_t num=1;
			for (auto e : t)
			{
				num *= 131;
				num +=e;
			}
			return num;

		}
	};
//开散列
namespace open_address
{

 //枚举三种状态
	enum State
	{
		Empty,
		Exist,
		Delete
	};
 //哈希节点
	template<class T>
	struct HashDateNode
	{
	private:
		T _kv;
		State _state=Empty;
	};
//哈希表
	template<class K, class T,class KeyofT,class DefaultHashFunc>
	class HashTable
	{
		typedef HashDateNode<T> Node;
		HashTable()//初始化,开辟10个空间
		{
			_Date.resize(10);
		}
		//插入数值
		bool insert(const T& Date)
		{

			DefaultHashFunc Func;//处理字符串问题
			KeyofT value;//处理set和map的数值问题函数
			//扩容
			if (n * 10 > _Date.size() * 7)//负载因子
			{
				int newsize = _Date.size() * 2;
				vector<Node*> newHT;
				newHT.resize(newsize);//开辟空间
				for (int i = 0; i < _Date.size(); i++)
				{
					if (_Date._state == Exist)//讲旧数据写入新空间中
					{
						newHT.insert(KetofT(_Date));
					}
					_Date.swap(newHT._Date);//交换数据
				}
			}
			//插入哈希表
			size_t hashi =Func(value(Date))% _Date.size();
			while (_Date[hashi]._state == Exist)//存在就++
			{
				++hashi;
				hashi %= _Date.size();
			}
			_Date[hashi]._kv = Date;
			_Date[hashi]._state = Exist;
			n++;//存放个数加一
			return true;
		}
		//查找函数
		vector<Node*> Find(const K& t)
		{
			
			DefaultHashFunc Func;
			KeyofT value;
			size_t hashi = Func(value(t)) % _Date.size();
			while (_Date[hashi]._state != Empty)
			{
				if (_Date[hashi]._state == Exist
					&& value(_Date[hashi]) == t)
				{
					return   _Date[hashi];
				}

				++hashi;
				hashi %= _Date.size();
			}

			return nullptr;

		}
 //删除
		bool erash(const K& key)
		{
			
			vector<Node*> ret = Find(key);//查找是否存在
			if (ret)
			{
				ret._state= Exist;
				n--;
				return true;
			}
			return false;
		}

	private:
		vector<Node*> _Date;//数据
		size_t n;//存储有效个数
	};
}

//哈希桶,闭散列
namespace hash_bucket
{
	template<class T> 
	struct HashDateNode
	{
		T _Date;
		HashDateNode<T>* _next;

		HashDateNode(const T& Date)
			:_Date(Date)
			,_next(nullptr)
		{}
	};
	
	template<class K, class T, class KeyofT, class HashFunc>
	class HashDate;//前置声明

	//迭代器
	//template<class K,class T,class KeyofT ,class HashFunc>//旧版
	template<class K, class T, class Ptr, class Ref, class KeyofT, class HashFunc>//新版
	struct HashIterator
	{
		typedef HashDateNode<T> Node;
		
		typedef HashIterator<K,T, Ptr, Ref,KeyofT, HashFunc> Self;
		typedef HashIterator<K, T, T*, T&, KeyofT, HashFunc> iterator;

		Node* _node;
		const HashDate<K, T, KeyofT, HashFunc>* _pht; //设置位const ,防止普通类型无法转化为const类型

		//初始化
		/*const HashIterator(Node* node, HashDate<K, T, KeyofT, HashFunc>* pht)
			:_node(node)
			, _pht(pht)
		{}*/

		//const初始化
		HashIterator(Node* node, const HashDate<K, T, KeyofT, HashFunc>*  pht)
			:_node(node)
			, _pht(pht)
		{}


		// 普通迭代器时,他是拷贝构造
		// const迭代器时,他是构造函数
		HashIterator(const iterator& it)//防止set类型的const类型与非const类型的转换(模板不同)
			:_node(it._node)
			, _pht(it._pht)
		{}


		Ref operator*()
		{
			return _node->_Date;
		}
		Ptr operator->()
		{
			return &_node->_Date;
		}
		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
			{
				HashFunc Func;
				KeyofT value;
				size_t hashi = Func(value(_node->_Date)) % _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;
		}

	};

	template<class K, class T, class KeyofT, class HashFunc = DefaultHashFunc<K>>
	class HashDate
	{
		typedef HashDateNode<T> Node;
		
		// 
		//友元
		template<class K, class T, class Ptr, class Ref, class KeyofT, class HashFunc>
		friend struct HashIterator;//可以使用迭代器

	public:
		typedef HashIterator<K, T, T*, T&, KeyofT, HashFunc> iterator;
		typedef HashIterator<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);
		}

		const_iterator begin() const
		{
			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 end() const
		{
			return iterator(nullptr, this);
		}
		HashDate()
		{
			_table.resize(10, nullptr);
		}

		~HashDate()
		{
			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& date)
		{
			
			KeyofT value;
			HashFunc Func;
			iterator it = Find(value(date));
			//it!=end()
			if(it != end())
			{
				return make_pair(it,false);
			}

			if (n == _table.size())//扩容
			{
				int newsize = _table.size() * 2;
				vector<Node*> newHash;
				newHash.resize(newsize);
				for (size_t i = 0; i < _table.size(); i++)//旧数据
				{
					Node* cur = _table[i];
					while (cur)
					{
						Node* next = cur->_next;
						size_t hashi = Func(value(cur->_Date))% newsize;
						cur->_next = newHash[hashi];
						newHash[hashi] = cur;
						cur = next;
					}
					_table[i] = nullptr;
				}
				_table.swap(newHash);//交换数据
			}
			//插入
			size_t hashi = Func(value(date))% _table.size();//改变
			//Node* cur = _table[hashi];
			//尾插
			//Node* newNode = new Node(date);
			//while (cur)
			//{
			//	cur = cur->_next;
			//}
			//cur = newNode;
			//头插
			Node* newNode = new Node(date);//新节点
			newNode->_next = _table[hashi];//头结点
			_table[hashi] = newNode;//尾节点
		
			n++;
			return make_pair(iterator(newNode,this),true);
		}


		//查找
		iterator Find(const K& key)//Find为K类型的只用一个数值,T类型的在map中为pair<K,T>类型
		{
			HashFunc Func;
			KeyofT value;
			size_t hashi = Func(key) % _table.size();
			//size_t hashi = Func(value(key)) % _table.size();//不能使用这个
			Node* cur = _table[hashi];
			while (cur)
			{
				if (value(cur->_Date) == key)//?
				{
					return iterator(cur,this);
				}
				cur = cur->_next;
			}
			return iterator(nullptr,this);
		}

		//删除
		bool Erase(const K& key)
		{
			HashFunc Func;
			KeyofT value;
			iterator ret=Find(key);
			if (ret == end())
				return true;
			size_t x = Func(value(key))% _table.size();
			Node* cur = _table[x];
			Node* prev = nullptr;
			while (cur)
			{
				if (value(cur->_Date) == key)
				{
					if (prev == nullptr)
					{
						_table[x] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					
				}
				prev = cur;
				cur = cur->_next;
				delete cur;
				return true;
			}
			return false;
		}
		//打印
		void Print()
		{
			for (int i = 10; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				while (cur)
				{
					std::cout << cur->_Date.first<<" " << cur->_Date.second <<" " << std::endl;
					cur = cur->_next;
				}
			}
			std::cout << std::endl;
		}

	private:
		vector<Node*> _table; //存储数据
		size_t n=0; //记录容器中的个数
	};
}

到了这里,关于C++--哈希表的实现及unorder_set和unorder_map的封装的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 由[哈希/散列]模拟实现[unordered_map/unordered_set] (手撕迭代器)

    以下两篇文章均为笔者的呕心沥血 想要搞懂本篇文章的uu请自行查阅 哈希/散列的细节实现 哈希/散列–哈希表[思想到结构][==修订版==] 手撕迭代器的细节处理 模拟实现map/set[改编红黑树实现map/set容器底层]

    2024年02月07日
    浏览(46)
  • [C++]哈希表实现,unordered_map\set封装

    目录 ​​​​​​​ 前言: 1 哈希 1.1 为什么有哈希 1.2 哈希结构 1.3 哈希冲突  2 闭散列 2.1 闭散列结点结构和位置状态表示 2.2 哈希类结构 2.3 插入 2.4 查找 2.5 删除 3 开散列 3.1 哈希表结点结构 3.2 哈希表结构 3.3 插入 3.4 查找、删除 3.5 迭代器实现 4 map和set的封装 4.1 map的封

    2024年02月08日
    浏览(49)
  • 【C++】开散列哈希表封装实现unordered_map和unordered_set

    在未达成目的之前,一切具有诱惑力的事物都显得那么不堪一击 1. 在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 l o g 2 N log_2 N l o g 2 ​ N ,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。 最好的查询是

    2023年04月09日
    浏览(84)
  • C++进阶--使用哈希表实现unordered_map和unordered_set的原理与实例

    本文将介绍如何使用哈希表来实现C++ STL库中的unordered_map和unordered_set容器。我们将会解释哈希表的基本原理,并给出具体的代码示例,帮助读者更好地理解和应用哈希表。 哈希原理讲解–链接入口 set和map的实现的文章,与unordered_map实现类似 unordered_set是一种集合存储的容器

    2024年04月09日
    浏览(46)
  • C++【unordered_map/set的底层实现-哈希表】—含有源代码

    前面讲了STL中的map和set容器以及封装实现,虽然它们的查找效率是O(logN),但是当红黑树中的节点非常多时,因为红黑树不是严格平衡,树的高度可能变得很大,就是一变高一边低的情况,这会导致查询操作的时间复杂度变为O(N),所以后面就出现了四个unordered系列的关联式容

    2024年02月08日
    浏览(45)
  • 改造哈希表,封装unordered_map和unordered_set

    正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能 学习网站, 通俗易懂,风趣幽默 ,忍不住分享一下给大家。点击跳转到网站。 unordered_map是存的是pair是K,V型的,而unordered_set是K型的,里面只存一个值,那我们如何利用一个数据结构将他们都封装出来呢?

    2024年02月03日
    浏览(48)
  • C++ 哈希+unordered_map+unordered_set+位图+布隆过滤器(深度剖析)

    想象一下,你有一个巨大的图书馆,里面摆满了成千上万本书。如果你想要找到其中一本特定的书,你会怎么做?如果你按照书的编号来有序地排列它们,找到特定的书本可能会很容易。但是,如果书籍是随机地摆放,你可能需要逐本地查找,这个过程会非常耗时。 而哈希函

    2024年02月21日
    浏览(55)
  • C++利用开散列哈希表封装unordered_set,unordered_map

    1.之前我们已经实现了开散列的哈希表,今天我们来用它封装unordered_set,unordered_map 2.本文的封装比利用红黑树封装set和map更加复杂 建议大家先去看我的红黑树封装set和map再来看本文 因为有很多地方跟红黑树封装set和map时是同样的思路和方法,所以本文不会太去赘述一遍 因为un

    2024年03月24日
    浏览(56)
  • 【C++】如何用一个哈希表同时封装出unordered_set与unordered_map

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》 《算法》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.哈希桶源码  2.哈希表模板参数的控制 3.字符串作为键值如何映射哈希值

    2024年03月26日
    浏览(52)
  • 【C++】STL——用一个哈希表封装出unordered_map和unordered_set

    根据先前对unordered_map和unordered_set的学习,我们得知其底层是借助哈希表来实现的,接下来我们会使用上篇博客实现的开散列哈希表来模拟实现unordered_map和unordered_set,哈希表源代码链接: Hash/Hash/HashBucket.h · wei/cplusplus - 码云 - 开源中国 (gitee.com) 下面我们对哈希表进行改造,

    2023年04月18日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包