哈希表封装myunordered_map以及set - 详解

1.unordered_set

1.仿函数

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

struct SetKeyOfT
{
	const K& operator()(const K& key)
	{
		return key;
	}
};

2.提供接口

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

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 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.成员变量

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

hash_bucket::HashTable _ht;

2.unordered_Map

1.仿函数

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

struct MapKeyOfT
{
	const K& operator()(const pair& kv)
	{
		return kv.first;
	}
};

2.接口函数

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

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

3.成员变量

hash_bucket::HashTable, MapKeyOfT, Hash> _ht;

4.前置声明

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

//前置声明
template
class HashTable;

3.HashTable

1.结点定义

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

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

2.迭代器操作

1.成员函数

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

typedef HashNode Node;
typedef HashTable HT;
typedef HTIterator Self;
Node* _node;
const HT* _ht;
HTIterator(Node* node,const HT* ht)
	:_node(node)
	,_ht(ht)
{}

2.++的实现

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

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类访问这个类的私有限定的内容

template
friend struct HTIterator;

2.Begin()

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

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.析构函数

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

		~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++,返回时用了隐式类型转换。

pair Insert(const T& data)
{
	KeyOft kot;
	Iterator it = Find(kot(data));
	if (it != End())
		return { it,false };
	Hash hash;
	if (_n == _tables.size())
	{
		vector 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().

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--。

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

#pragma once
#include
template
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};
template<>
struct HashFunc
{
	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
	struct HashNode
	{
		T _data;
		HashNode* _next;
		HashNode(const T& data)
			:_data(data)
			,_next(nullptr)
		{}
	};
	//前置声明
	template
	class HashTable;
	template
	struct HTIterator
	{
		typedef HashNode Node;
		typedef HashTable HT;
		typedef HTIterator 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 HashTable
	{
		//友元声明
		template
		friend struct HTIterator;
		typedef HashNode Node;
	public:
		typedef HTIterator Iterator; //你的这里是大写的
		typedef HTIterator 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 Insert(const T& data)
		{
			KeyOft kot;
			Iterator it = Find(kot(data));
			if (it != End())
				return { it,false };
			Hash hash;
			if (_n == _tables.size())
			{
				vector 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 _tables;
			size_t _n = 0;
	};
}

Unordered_set

#pragma once
#include"HashTable.h"
namespace bit
{
	template>
	class unordered_set
	{
		struct SetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename hash_bucket::HashTable::Iterator iterator;
		typedef typename hash_bucket::HashTable::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 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 _ht;
	};
	void print(const unordered_set& s)
	{
		unordered_set::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 s;
		for (auto e : a)
		{
			s.insert(e);
		}
		unordered_set::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

#pragma once
#include"HashTable.h"
namespace bit
{
	template>
	class unordered_map
	{
		struct MapKeyOfT
		{
			const K& operator()(const pair& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename hash_bucket::HashTable,MapKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable,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 ret = insert({ key,V() });
			return ret.first->second;
		}
		pair insert(const pair& 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, MapKeyOfT, Hash> _ht;
	};
	void test_map1()
	{
		unordered_map 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::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

#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
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 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 ht1;
//	for (auto& e : a1)
//	{
//		ht1.Insert({ e, e });
//	}
//
//	cout << HashFunc()("abcd") << endl;
//	cout << HashFunc()("bcad") << endl;
//	cout << HashFunc()("aadd") << endl;
//
//	int a2[] = { -19,-30,5,36,13,20,21,12 };
//	HashTable ht2;
//	for (auto e : a2)
//	{
//		ht2.Insert({ e, e });
//	}
//
//	// 哈希冲突
//	HashTable 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;
}

posted on 2025-11-20 18:24  ljbguanli  阅读(0)  评论(0)    收藏  举报