当前位置: 首页 > article >正文

unordered_set 和unordered_map的模拟实现(使用开散列)

实现步骤:(与红黑树实现set相似)

1、实现哈希表

2、封装unordered_map和unordered_set 解决KeyOfT

3、iterator

4、const_iterator

5、修改key的问题

6、operator[ ]

开散列的实现

#pragma once
#include<iostream>
#include<vector>
using namespace std;
	//  1、实现哈希表
	//  2、封装unordered_map和unordered_set  解决KeyOfT
	//  3、iterator
	//  4、const_iterator
	//  5、修改key的问题
	//  6、operator[]


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

// 特化
template<>
struct HashFunc<string>
{
	size_t operator()(const string& key)
	{
		size_t hash = 0;
		for (auto e : key)
		{
			hash *= 31;
			hash += e;
		}

		return hash;
	}
};
namespace HashBucket
{
	


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

	//解决相互依赖,前置声明
	template<class K, class T, class KeyOfT, class Hash>
	class HashTable;

	template< class K ,class T, class Ptr ,class Ref,class KeyOfT ,class Hash>
	struct HashTableIterator
	{
		typedef HashNode<K, T> Node;
		typedef HashTableIterator<K, T ,Ptr ,Ref, KeyOfT, Hash> Self;

		HashNode<K, T>* _node;
		const HashTable<K, T, KeyOfT , Hash>* _pHashTable;//因为要往下遍历所以要有类对象的指针this,来使用vector

		HashTableIterator(Node* node ,const HashTable<K, T, KeyOfT ,Hash>* Phst )
			:_node(node)
			, _pHashTable(Phst)
		{}

		Self& operator++()
		{
			if (_node->_next)//此桶不为空
			{
				_node = _node->_next;
			}
			else//此桶为空 ,找下一个不为空的桶
			{
				//算出哈希值
				KeyOfT Kot;
				Hash hs;
				size_t hashi = hs(Kot(_node->_data)) % _pHashTable->_table.size();//_table 是HashTable的私有,用友元
				++hashi;
				while (hashi< _pHashTable->_table.size())
				{
					if (_pHashTable->_table[hashi])
					{
						break;
					}
					++hashi;
				}
														//容易忘
				if (hashi == _pHashTable->_table.size())//加到最后也没有找到返回end()
				{
					_node = nullptr;
				}
				else
				{
					_node = _pHashTable->_table[hashi];
				}
			}

			return *this;
		}

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

		bool operator!=(const Self & Interator)
		{
			return _node != Interator._node;
		}

		bool operator == (const Self & Interator)
		{
			return _node == Interator._node;
		}

		
	};

	template<class K, class T,  class KeyOfT ,class Hash >
	class HashTable
	{
		typedef HashNode<K, T> Node;
		//友元 ,类模板的友元要带参数template<class ...>
		template< class K, class T, class Ptr, class Ref,class KeyOfT, class Hash>
		friend struct HashTableIterator;

	public:
		typedef HashTableIterator<K, T ,T* ,T& , KeyOfT, Hash> Iterator;
		typedef HashTableIterator<K, T, const T*,const  T&, KeyOfT, Hash> ConstIterator;

		HashTable()
		{
			_table.resize(10, nullptr);
		}

		~HashTable()
		{
			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				while (cur)
				{
					Node* next = cur->_next;
					delete cur;
					cur = next;
				}
				_table[i] = nullptr;
			}
		}

		Iterator Begin()
		{				//容易忘
			if (_n == 0)//没有值直接返回空
			{
				return End();
			}
			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				if (cur)
				{
					return Iterator(cur, this);
				}
			}
			return End();
		}

		Iterator End()
		{
			return Iterator(nullptr ,this);
		}
		ConstIterator Begin() const
		{
			if (_n == 0)//没有值直接返回空
			{
				return End();
			}
			for (size_t i = 0; i < _table.size(); i++)
			{
				Node* cur = _table[i];
				if (cur)
				{
					return ConstIterator(cur, this);
				}
			}
			return End();
		}

		ConstIterator End()const
		{
			return ConstIterator(nullptr, this);
		}

		pair<Iterator ,bool> Insert(const T& data)
		{
			Hash hs;
			KeyOfT Kot;
			Iterator it = Find(Kot(data));
			if ( it !=  End())
			{
				return make_pair(it ,false);
			}
			size_t hashi = hs(Kot(data)) % _table.size();
			//负载因子等于1就扩容,这里的扩容与散列表(开放地址)扩容不同
			//如果复用Insert ,这里的结点都需要重新new 和delete,效率太低,代价太大
			//使用挪动节点的方法
			if (_n == _table.size())
			{
				/*HashTable<K, V> newhs;//效率低
				newhs._table.resize(2*_table.size(),nullptr);
				for (size_t i = 0; i < _table.size(); i++)
				{
					Node* cur = _table[i];
					while(cur)
					{
						newhs.Insert(cur->_kv);
						cur = cur->_next;
					}
				}
				_table.swap(newhs._table);*/

				vector<Node*> newtable(_table.size() * 2, nullptr);
				for (size_t i = 0; i < _table.size(); i++)
				{
					Node* cur = _table[i];
					while (cur)
					{	//存储旧表的下一个,便于循环
						Node* curnext = cur->_next;
						//在新表中的映射
						Hash hs;
						KeyOfT Kot;
						size_t hashi = hs(Kot(cur->_data)) % newtable.size();

						Node* newnext = newtable[hashi];
						newtable[hashi] = cur;
						cur->_next = newnext;

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

		
			Node* newnode = new Node(data);
			Node* next = _table[hashi];
			_table[hashi] = newnode;//进行头插,不用找尾了
			newnode->_next = next;
			++_n;

			return make_pair(Iterator(newnode,this ), true);
		}

		Iterator Find(const K& key)
		{
			Hash hs;
			KeyOfT Kot;
			size_t hashi = hs(key) % _table.size();
			Node* cur = _table[hashi];
			while (cur)
			{
				if (Kot(cur->_data) == key)
				{
					return Iterator(cur ,this);
				}
				cur = cur->_next;
			}
			return End();
		}

		bool Erase(const K& key)
		{
			Hash hs;
			KeyOfT Kot;
			size_t hashi = hs(key) % _table.size();
			Node* prev = nullptr;//用于判断删除节点位于链表第一个位置,还是中间位置(最后位置与中间位置处理方法一致)
			Node* cur = _table[hashi];
			while (cur)
			{
				if (Kot(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						_table[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					--_n;//容易忘
					return true;
				}

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

	private:
		vector<HashNode<K, T>*> _table;//指针数组
		size_t _n = 0;
	};
}

unordered_set的实现

#pragma once
#include"MyHash.h"

namespace BMH
{
	
	template<class K , class Hash = HashFunc<K>>
	class unordered_set
	{

		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename HashBucket::HashTable< K,const K, SetKeyOfT, Hash>::Iterator iterator;//将第二个模板参数传成const,使set的key不能修改
		typedef typename HashBucket::HashTable< K,const K, SetKeyOfT, Hash>::ConstIterator const_iterator;//将第二个模板参数传成const

		iterator begin()
		{
			return _hst.Begin();
		}

		iterator end()
		{
			return _hst.End();
		}

		const_iterator begin() const
		{
			return _hst.Begin();
		}

		const_iterator end() const
		{
			return _hst.End();
		}

		pair<iterator, bool> insert(const K& key)
		{
			return _hst.Insert(key);
		}

		iterator find(const K& key)
		{
			return _hst.Find(key);
		}
		bool erase(const K& key)
		{
			return _hst.Erase(key);
		}

	private:
		HashBucket::HashTable< K,const K, SetKeyOfT, Hash>  _hst; // 将第二个模板参数传成const, 使set的key不能修改
	};

	struct Date
	{
		int _year;
		int _month;
		int _day;

		bool operator==(const Date& d) const
		{
			return _year == d._year
				&& _month == d._month
				&& _day == d._day;
		}
	};

	struct HashDate
	{
		size_t operator()(const Date& date)
		{
			return (((date._year * 31) + date._month) * 31) + date._day;
		}
	};

	void Print(const BMH::unordered_set<int>& s)
	{
		BMH::unordered_set<int>::const_iterator it = s.begin();
		while (it != s.end())
		{
			//*it += 2;  set不能修改
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}
	void test_set()
	{
		BMH::unordered_set<int> s;
		int a[] = {4,2,6,1,3,5,15,7,16,14 ,3,3,15,15};
		for (auto e : a)
		{
			s.insert(e);
		}
		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;


		BMH::unordered_set<int>::iterator it = s.begin();
		//*it += 10;
		while (it != s.end())
		{
			cout << *it << " ";
			//*it += 10;//set应该不能改key
			++it;
		}
		cout << endl;
		Print(s);

	/*	for (auto e : a)
		{
			s.erase(e);
		}

		for (auto e : s)
		{
			cout << e << " ";
		}
		cout << endl;*/

		BMH::unordered_set<Date, HashDate> sdate;
		sdate.insert({2024,11,22});
		sdate.insert({2024,11,23});

	}
}

unordered_map的实现

#pragma once
#include"MyHash.h"

namespace BMH
{
	template<class K ,class V ,class Hash = HashFunc<K>>
	class unordered_map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair<K,V>& kv)
			{
				return kv.first;
			}
		};
	public:

		typedef typename HashBucket::HashTable<  K, pair<const K, V>, MapKeyOfT , Hash>::Iterator iterator;// 将pair的第1个模板参数传成const, 使pair的key不能修改能修改
		typedef typename HashBucket::HashTable< K, pair<const K, V>, MapKeyOfT, Hash>::ConstIterator const_iterator;// 将pair的第1个模板参数传成const, 使pair的key不能修改

		iterator begin()
		{
			return _hst.Begin();
		}

		iterator end()
		{
			return _hst.End();
		}

		const_iterator begin() const
		{
			return _hst.Begin();
		}

		const_iterator end() const
		{
			return _hst.End();
		}

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

		V& operator[](const K& key)
		{
			pair<iterator, bool > ret = _hst.Insert(make_pair(key,V()));
			return ret.first->second;
		}

		iterator find(const K& key)
		{
			return _hst.Find(key);
		}
		bool erase(const K& key)
		{
			return _hst.Erase(key);
		}


	private:
		HashBucket::HashTable< K, pair<const K ,V> , MapKeyOfT , Hash>  _hst;// 将pair的第1个模板参数传成const, 使pair的key不能修改
	};

	void test_map()
	{
		BMH::unordered_map<string, string> dict;
		dict.insert({ "sort", "排序" });
		dict.insert({ "left", "左边" });
		dict.insert({ "right", "右边" });

		dict["left"] = "左边,剩余";
		dict["insert"] = "插入";
		dict["string"];

		BMH::unordered_map<string, string>::iterator it = dict.begin();
		while (it != dict.end())
		{
			// 不能修改first,可以修改second
			//it->first += 'x';
			it->second += 'x';

			cout << it->first << ":" << it->second << endl;
			++it;
		}
		cout << endl;

			dict.erase("sort");
			dict.erase("left");
			dict.erase("insert");
			dict.erase("right");
			dict.erase("string");
			BMH::unordered_map<string, string>::iterator it2 = dict.begin();
			while (it2 != dict.end())
			{
				cout << it2->first << ":" << it2->second << endl;
				++it2;
			}
	}
}

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助

欢迎各位点赞,收藏和关注哦

如果有疑问或有不同见解,欢迎在评论区留言哦

后续我会一直分享双一流211西北大学软件(C,数据结构,C++,Linux,MySQL)的学习干货以及重要代码的分享


http://www.kler.cn/a/410009.html

相关文章:

  • 基于物联网的农业环境监测系统开发(本科毕业论文)
  • 对象排序得到方式
  • 蒙特卡洛方法(Monte Carlo,MC)
  • 音视频基础扫盲之视频码率控制策略(CBR、VBR还是ABR)
  • c API【MySQL】
  • 项目缓存之Caffeine咖啡因
  • 【数据分析】认清、明确
  • Oracle 深入学习 Part 7: Maintaining Online Redo Log Files(维护联机重做日志文件)
  • Linux网络编程----使用多进程实现并发服务器
  • 【Leetcode 每日一题】146. LRU 缓存(c++)
  • Django快速上手:从零到一构建Web应用
  • HTMLCSS:彩色灵动气泡效果
  • Redis的管道操作
  • 小程序-基于java+SpringBoot+Vue的农场管理系统设计与实现
  • I.MX6U 裸机开发20. DDR3 内存知识
  • 模拟器多开限制ip,如何设置单窗口单ip,每个窗口ip不同
  • Oracle RMAN克隆数据库(同主机)
  • 硬件基础22 反馈放大电路
  • 深入解析信号量:定义与环形队列生产消费模型剖析
  • 深入理解B-树与B+树:数据结构中的高效索引利器