哈希表封装myunordered_map以及set

1.unordered_set

1.仿函数

这个是为了把对象的键值取出来

cpp 复制代码
struct SetKeyOfT
{
	const K& operator()(const K& key)
	{
		return key;
	}
};

2.提供接口

把封装好的函数在调用,调用的函数为接口

cpp 复制代码
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 K& key)
{
	return _ht.Insert(key);
}

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

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

3.成员变量

再主函数里得到模板的参数,确定了每个变量的具体类型

cpp 复制代码
hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;

2.unordered_Map

1.仿函数

对于键值对,要单独取出键值来

cpp 复制代码
struct MapKeyOfT
{
	const K& operator()(const pair<K, V>& kv)
	{
		return kv.first;
	}
};

2.接口函数

下标访问先用插入函数去找到位置,因为插入函数插入失败与成功都会返回当前位置的pair,pair的first是迭代器,而迭代器又是结点的指针,所以用->重载函数可以得到指定的结点,而结点也是pair,second就是值。

cpp 复制代码
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)
{
	pair<iterator, bool> ret = insert({ key,V() });
	return ret.first->second;
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
	return _ht.Insert(kv);
}

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

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

3.成员变量

cpp 复制代码
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;

4.前置声明

因为只有类内部才可以不用向上查找,所以要前置声明是编译器知道有这个类存在。

cpp 复制代码
//前置声明
template<class K,class T,class KeyOft,class Hash>
class HashTable;

3.HashTable

1.结点定义

这里T是数据的类型,T会在哈希表的类里面知道

cpp 复制代码
template<class T>
struct HashNode
{
	T _data;
	HashNode<T>* _next;

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

};

2.迭代器操作

1.成员函数

结点的指针和哈希表的指针

cpp 复制代码
typedef HashNode<T> Node;
typedef HashTable<K, T, KeyOft, Hash> HT;
typedef HTIterator<K,T, Ref, Ptr, KeyOft, Hash> Self;
Node* _node;
const HT* _ht;

HTIterator(Node* node,const HT* ht)
	:_node(node)
	,_ht(ht)
{}

2.++的实现

判断结点的下一个是否为空,为空就直接往下走一格,不为空就要到下一个地方去,比如2走完了就要去8的位置,先计算出此位置的哈希值,然后通过循环遍历,只要把哈希值+1就会到下一个地方,就一直加,直到找到不为空的地方,还需要判断最后的哈希值是否跟哈希表的大小一样,一样就说明上面的循环不是break出来的而是条件不符合出来的,则把指针_node指向nullptr,最后返回*this,也就是这个类的对象此位置的迭代器。

cpp 复制代码
Self& operator++()
{
	if (_node->_next)
	{
		_node = _node->_next;
	}
	else
	{
		KeyOft kot;
		Hash hash;
		size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();
		++hashi;
		while (hashi < _ht->_tables.size())
		{
			_node = _ht->_tables[hashi];
			if (_node)
				break;
			++hashi;
		}
		if (hashi == _ht->_tables.size())
		{
			_node = nullptr;
		}
	}
	return *this;
}

4.HashTable

1.友元声明

可以让HTIterator类访问这个类的私有限定的内容

cpp 复制代码
template<class K,class T,class Ref,class Ptr,class Keyft,class Hash>
friend struct HTIterator;

2.Begin()

如果没有插入一个则直接返回End(),有则需要循环去遍历找到第一个的位置,找到就返回迭代器,这里的this是类的对象,也就是指向HashTable的指针。

cpp 复制代码
Iterator Begin()
{
	if (_n == 0)
		return End();
	for (size_t i = 0; i <_tables.size(); i++)
	{
		Node* cur = _tables[i];
		if (cur)
			return Iterator(cur, this);
	}
	return End();
}

Iterator End()
{
	return Iterator(nullptr, this);
}

3.析构函数

因为哈希桶可能一个位置挂了多个结点在下面,所以要循环去把当前位置的结点删除,再去遍历哈希表找到下一个存在桶的位置。

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

		}

4.Insert函数

插入前需要判断是否存在当前的哈希表里,用Find函数去查找,返回的迭代器不等于End就说明存在,不能插入,如果负载因子等于1需要扩容,通过素数表得到空间大小,接着是把旧表内容移到新表,kot得到键值,hash得到哈希值,双重仿函数,cur->next是把旧表结点指向新表的位置,然后结点指针取代新表的指针,每一个新来的都会头插,插入成功还要把_n++,返回时用了隐式类型转换。

cpp 复制代码
pair<Iterator, bool> Insert(const T& data)
{
	KeyOft kot;
	Iterator it = Find(kot(data));
	if (it != End())
		return { it,false };

	Hash hash;

	if (_n == _tables.size())
	{
		vector<Node*> newTable(__stl_next_prime(_tables.size() + 1));
		for (size_t i = 0; i < _tables.size(); i++)
		{
			Node* cur = _tables[i];
			while (cur)
			{
				Node* next = cur->_next;
				size_t hashi = hash(kot(cur->_data)) % newTable.size();
				cur->_next = newTable[hashi];
				newTable[hashi] = cur;
				cur = next;
			}
			_tables[i] = nullptr;
		}
		_tables.swap(newTable);
	}

	size_t hashi = hash(kot(data)) % _tables.size();

	Node* newnode = new Node(data);
	newnode->_next = _tables[hashi];
	_tables[hashi] = newnode;

	++_n;
	return { Iterator(newnode,this),true };
}

5.Find函数

通过给的键值计算出哈希值找到对应的挂载结点的位置,接着去遍历结点找到指定结点,遍历结束则没有找到就返回End().

cpp 复制代码
Iterator Find(const K& key)
{
	KeyOft kot;
	Hash hash;
	size_t hashi = hash(key) % _tables.size();
	Node* cur = _tables[hashi];
	while (cur)
	{
		if (kot(cur->_data) == key)
			return Iterator(cur, this);
		cur = cur->_next;
	}
	return End();
}

6.Erase函数

这里需要设置一个prev变量,如果删除的结点是在中间的话就需要把前一个和后一个接在一起,先得到哈希值找到挂载结点的位置,然后循环遍历找指定结点,如果prev变量还是nullptr就说明是第一个结点删除,删除后要把_n--。

cpp 复制代码
bool Erase(const K& key)
{
	KeyOft kot;
	size_t hashi = key % _tables.size();
	Node* prev = nullptr;
	Node* cur = _tables[hashi];
	while (cur)
	{
		if (kot(cur->_data) == key)
		{
			if (prev == nullptr)
			{
				_tables[hashi] = cur->_next;
			}
			else
			{
				prev->_next = cur->_next;
			}
			delete cur;
			--_n;
			return true;
		}
		else
		{
			prev = cur;
			cur = cur->_next;
		}


	}
	return false;
}

5.总代码

HashTable

cpp 复制代码
#pragma once

#include<vector>



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)
	{
		// BKDR
		size_t hash = 0;
		for (auto ch : s)
		{
			hash += ch;
			hash *= 131;
		}

		return hash;
	}
};


//
//
//
//
//
inline unsigned long __stl_next_prime(unsigned long n)
{
	// Note: assumes long is at least 32 bits.
	static const int __stl_num_primes = 28;
	static const unsigned long __stl_prime_list[__stl_num_primes] = {
		53, 97, 193, 389, 769,
		1543, 3079, 6151, 12289, 24593,
		49157, 98317, 196613, 393241, 786433,
		1572869, 3145739, 6291469, 12582917, 25165843,
		50331653, 100663319, 201326611, 402653189, 805306457,
		1610612741, 3221225473, 4294967291
	};
	const unsigned long* first = __stl_prime_list;
	const unsigned long* last = __stl_prime_list + __stl_num_primes;
	const unsigned long* pos = lower_bound(first, last, n);
	return pos == last ? *(last - 1) : *pos;
}

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

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

	};
	//前置声明
	template<class K,class T,class KeyOft,class Hash>
	class HashTable;

	template<class K,class T,class Ref,class Ptr,class KeyOft,class Hash>
	struct HTIterator
	{
		typedef HashNode<T> Node;
		typedef HashTable<K, T, KeyOft, Hash> HT;
		typedef HTIterator<K,T, Ref, Ptr, KeyOft, Hash> Self;

		Node* _node;
		const HT* _ht;

		HTIterator(Node* node,const HT* ht)
			:_node(node)
			,_ht(ht)
		{}
		Ref operator*()
		{
			return _node->_data;
		}

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

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

		Self& operator++()
		{
			if (_node->_next)
			{
				_node = _node->_next;
			}
			else
			{
				KeyOft kot;
				Hash hash;
				size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();
				++hashi;
				while (hashi < _ht->_tables.size())
				{
					_node = _ht->_tables[hashi];
					if (_node)
						break;
					++hashi;
				}
				if (hashi == _ht->_tables.size())
				{
					_node = nullptr;
				}
			}
			return *this;
		}
		
	};
	template<class K,class T,class KeyOft,class Hash>
	class HashTable
	{
		//友元声明
		template<class K,class T,class Ref,class Ptr,class Keyft,class Hash>
		friend struct HTIterator;
		typedef HashNode<T> Node;
	public:
		typedef HTIterator<K, T, T&, T*, KeyOft, Hash> Iterator; //你的这里是大写的 
		typedef HTIterator<K, T, const T&, const T*, KeyOft, Hash> ConstIterator;

		Iterator Begin()
		{
			if (_n == 0)
				return End();
			for (size_t i = 0; i <_tables.size(); i++)
			{
				Node* cur = _tables[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 < _tables.size(); i++)
			{
				Node* cur = _tables[i];
				if (cur)
				{
					return ConstIterator(cur, this);
				}
			}

			return End();
		}

		ConstIterator End() const
		{
			return ConstIterator(nullptr, this);
		}
		HashTable()
			:_tables(__stl_next_prime(0))
			, _n(0)
		{}

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

		}
		pair<Iterator, bool> Insert(const T& data)
		{
			KeyOft kot;
			Iterator it = Find(kot(data));
			if (it != End())
				return { it,false };

			Hash hash;

			if (_n == _tables.size())
			{
				vector<Node*> newTable(__stl_next_prime(_tables.size() + 1));
				for (size_t i = 0; i < _tables.size(); i++)
				{
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;
						size_t hashi = hash(kot(cur->_data)) % newTable.size();
						cur->_next = newTable[hashi];
						newTable[hashi] = cur;
						cur = next;
					}
					_tables[i] = nullptr;
				}
				_tables.swap(newTable);
			}

			size_t hashi = hash(kot(data)) % _tables.size();

			Node* newnode = new Node(data);
			newnode->_next = _tables[hashi];
			_tables[hashi] = newnode;

			++_n;
			return { Iterator(newnode,this),true };
		}
		Iterator Find(const K& key)
		{
			KeyOft kot;
			Hash hash;
			size_t hashi = hash(key) % _tables.size();
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
					return Iterator(cur, this);
				cur = cur->_next;
			}
			return End();
		}

		bool Erase(const K& key)
		{
			KeyOft kot;
			size_t hashi = key % _tables.size();
			Node* prev = nullptr;
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						_tables[hashi] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					--_n;
					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}


			}
			return false;
		}
		private:
			vector<Node*> _tables;
			size_t _n = 0;

	};
}

Unordered_set

cpp 复制代码
#pragma once

#include"HashTable.h"

namespace bit
{
	template<class K, class Hash = HashFunc<K>>
	class unordered_set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::ConstIterator const_iterator;

		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 K& key)
		{
			return _ht.Insert(key);
		}

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

		bool Erase(const K& key)
		{
			return _ht.Erase(key);
		}
	private:
		hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
	};

	void print(const unordered_set<int>& s)
	{
		unordered_set<int>::const_iterator it = s.begin();
		while (it != s.end())
		{
			//*it = 1;
			cout << *it << " ";
			++it;
		}
		cout << endl;

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

	void test_set1()
	{
		int a[] = { 3,11,86,7,88,82,1,881,5,6,7,6 };
		unordered_set<int> s;
		for (auto e : a)
		{
			s.insert(e);
		}

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

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

		print(s);
	}
}

Unordered_map

cpp 复制代码
#pragma once

#include"HashTable.h"

namespace bit
{
	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 hash_bucket::HashTable<K, pair<const K, V>,MapKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable<K, pair<const K, V>,MapKeyOfT, Hash>::ConstIterator const_iterator;
		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)
		{
			pair<iterator, bool> ret = insert({ key,V() });
			return ret.first->second;
		}
		pair<iterator, bool> insert(const pair<K, V>& kv)
		{
			return _ht.Insert(kv);
		}

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

		bool Erase(const K& key)
		{
			return _ht.Erase(key);
		}
	private:
		hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;

	
	};
	void test_map1()
	{
		unordered_map<string, string> dict;
		dict.insert({ "sort", "排序" });
		dict.insert({ "字符串", "string" });

		dict.insert({ "sort", "排序" });
		dict.insert({ "left", "左边" });
		dict.insert({ "right", "右边" });

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

		for (auto& kv : dict)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;

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

test

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<set>
#include<unordered_set>

using namespace std;



#include"HashTable.h"

//int main()
//{
//	//int a[] = { 19,30,52,63,11,22 };
//	int a[] = { 19,30,5,36,13,20,21,12 };
//	HashTable<int, int> ht;
//	for (auto e : a)
//	{
//		ht.Insert({ e, e });
//	}
//
//	//ht.Insert({ 15, 15 });
//
//	ht.Erase(30);
//	if (ht.Find(20))
//	{
//		cout << "找到了" << endl;
//	}
//
//	if (ht.Find(30))
//	{
//		cout << "找到了" << endl;
//	}
//	else
//	{
//		cout << "没有找到" << endl;
//	}
//
//	return 0;
//}

//struct StringHashFunc
//{
//	size_t operator()(const string& s)
//	{
//		size_t hash = 0;
//		for (auto ch : s)
//		{
//			hash += ch;
//		}
//
//		return hash;
//	}
//};

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

	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

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

struct DateHashFunc
{
	size_t operator()(const Date& d)
	{
		size_t hash = 0;
		hash += d._year;
		hash *= 131;

		hash += d._month;
		hash *= 131;

		hash += d._day;
		hash *= 131;

		return hash;
	}
};

//int main()
//{
//	//int a[] = { 19,30,52,63,11,22 };
//	
//	const char* a1[] = { "abcd", "sort", "insert" };
//	HashTable<string, string> ht1;
//	for (auto& e : a1)
//	{
//		ht1.Insert({ e, e });
//	}
//
//	cout << HashFunc<string>()("abcd") << endl;
//	cout << HashFunc<string>()("bcad") << endl;
//	cout << HashFunc<string>()("aadd") << endl;
//
//	int a2[] = { -19,-30,5,36,13,20,21,12 };
//	HashTable<int, int> ht2;
//	for (auto e : a2)
//	{
//		ht2.Insert({ e, e });
//	}
//
//	// 哈希冲突
//	HashTable<Date, int, DateHashFunc> ht;
//	ht.Insert({ { 2024, 10, 12 }, 1});
//	ht.Insert({ { 2024, 12, 10 }, 1 });
//
//	return 0;
//}

#include"Unordered_map.h"



#include"Unordered_set.h"
int main()
{


	//bit::test_set1();
	bit::test_map1();


	return 0;
}
相关推荐
海绵宝宝的好伙伴3 小时前
【数据结构】哈希表的理论与实现
数据结构·哈希算法·散列表
Aqua Cheng.3 小时前
代码随想录第七天|哈希表part02--454.四数相加II、383. 赎金信、15. 三数之和、18. 四数之和
java·数据结构·算法·散列表
怀揣小梦想3 小时前
跟着Carl学算法--哈希表
数据结构·c++·笔记·算法·哈希算法·散列表
Kent_J_Truman3 小时前
【模拟散列表】
数据结构·算法·蓝桥杯·散列表·常识类
努力努力再努力wz3 小时前
【C++进阶系列】:万字详解unordered_set和unordered_map,带你手搓一个哈希表!(附模拟实现unordered_set和unordered_map的源码)
java·linux·开发语言·数据结构·数据库·c++·散列表
加油=^_^=3 小时前
【C++】哈希表
数据结构·c++·散列表
对纯音乐情有独钟的阿甘3 小时前
【C++庖丁解牛】哈希表/散列表的设计原理 | 哈希函数
c++·哈希算法·散列表
励志不掉头发的内向程序员3 小时前
【STL库】哈希表的原理 | 哈希表模拟实现
开发语言·c++·学习·散列表
普通网友3 小时前
哈希表:高效存储与查找的核心原理
数据结构·哈希算法·散列表·csdn