详解c++---哈希封装

哈希桶的代码

通过前面的学习大家应该能够很容易的写出下面的代码:

#pragma once
#include<iostream>
#include<vector>
using namespace std;
template<class K,class V>
struct HashNode
{
    
    
	HashNode(const pair<K,V>& kv)
		:_kv(kv)
		,_next(nullptr)
	{
    
    }
	pair<K, V> _kv;
	HashNode* _next;
};
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)
	{
    
    
		size_t res = 0;
		for (auto& ch : s)
		{
    
    
			res *= 131;
			res += ch;
		}
		return res;
	}
};
template<class K, class V, class Hash = HashFunc<K>>
class BucketTable
{
    
    
	typedef HashNode<K, V> Node;
public:
	BucketTable()
		:_n(0)
	{
    
    
		_tables.resize(__stl_next_prime(_tables.size()));
	}
	Node* Find(const K& key)
	{
    
    
		Hash hf;
		size_t pos = hf(key) % _tables.size();
		Node* cur = _tables[pos];
		while (cur)
		{
    
    
			if (cur->_kv.first == key)
			{
    
    
				return cur;
			}
			else
			{
    
    
				cur = cur->_next;
			}
		}
		return nullptr;
	}
	bool insert(const pair<K, V>& kv)
	{
    
    
		if (Find(kv.first))
		{
    
    
			return false;
		}
		if (_n / _tables.size() == 1)//平衡因子为1就更新
		{
    
    
			vector<Node*> newBH;
			newBH.resize(__stl_next_prime(_tables.size()));
			for (int i = 0; i < _tables.size(); i++)
			{
    
    
				Node* cur = _tables[i];
				while (cur)
				{
    
    
					Node* next = cur->_next;
					size_t pos = Hash()(cur->_kv.first);
					cur->_next = newBH[pos];
					newBH[pos] = cur;
					cur = next;
				}
				_tables[i] = nullptr;
			}
		}
		Hash hf;
		size_t pos = hf(kv.first) % _tables.size();
		Node* newnode = new HashNode<K,V>(kv);
		newnode->_next = _tables[pos];
		_tables[pos] = newnode;
		++_n;
		return true;
	}
	bool erase(const K& key)
	{
    
    
		HashFunc<K> HF;
		size_t pos = HF(key) % _tables.size();
		Node* cur = _tables[pos];
		Node* prev = cur;
		while (cur)
		{
    
    
			if (cur->_kv.first == key)
			{
    
    
				if (cur == _tables[pos])
				{
    
    
					_tables[pos] = cur->_next;
				}
				else
				{
    
    
					prev->_next = cur->_next;
				}
				delete cur;
				_n--;
				return true;
			}
			else
			{
    
    
				prev = cur;
				cur = cur->_next;
			}
		}
		return false;
	}
	~BucketTable()
	{
    
    
		for (int i = 0; i < _tables.size(); i++)
		{
    
    
			Node* cur = _tables[i];
			while (cur)
			{
    
    
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
			_tables[i] = nullptr;
		}
	}
	inline unsigned long __stl_next_prime(unsigned long n)
	{
    
    
		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
		};
		for (int i = 0; i < __stl_num_primes; ++i)
		{
    
    
			if (__stl_prime_list[i] > n)
			{
    
    
				return __stl_prime_list[i];
			}
		}
		return __stl_prime_list[__stl_num_primes - 1];
	}


private:
	vector<Node*> _tables;
	size_t _n;
};

哈希桶的修改

首先我们这里得使用哈希桶来封装出来set和map,根据前面红黑树的经验我们知道虽然set容器内部只存放一种数据,但是在封装的时候依然得使用两个模板参数来对数据进行封装,因为insert函数的参数得是value,而find函数的参数是key,所以为了保证封装时候的统一性这里就采用两个参数来表示哈希桶中的内部数据,对于set容器节点模板的两个参数都是key,对于map容器节点模板的两个参数则是key和value,那么描述节点类的代码就如下:

template<class T>
struct HashNode
{
    
    
	HashNode(const T& data)
		:_data(data)
		, _next(nullptr)
	{
    
    }
	T _data;//这里的_data既可以是map的内部数据也可以是set的内部数据
	HashNode* _next;
};

既然节点类发生了修改,那么哈希桶的insert函数也得做出修改将原来参数的pair类型转换成为模板的第二个类型T,又因为第二个参数可能存储的是pair也可能存储的是key,但是find函数和insert函数之前一直都是用pair的第一个参数来进行比较,所以这里得添加一个仿函数参数来获取容器内部数据的key值,并且insert函数,find函数,erase函数都是通过创建仿函数对象来进行数据的比较,所以这里得一一做出更改,将之前手动通过pair获取first数据的方式修改成为通过仿函数来获取key,比如原来是这样的:cur->_kv.first,那么修改之后就应该变成了下面这样:kot(cur->_data)将上面哈希桶的全部的这样情况都进行修改就完成了第一步,接下来就实现unorderedmap和unorderedset的类的实现,首先这两个类都是基于哈希桶来实现的,所以这两个类中都一个哈希桶的私有变量, 其次我们使用哈希表的时候可以传递不同的仿函数,所以这里的类也得添加一个仿函数的模板参数,又因为哈希桶需要一个仿函数来获取数据中的key,所以在外层的set和map容器得创建一个仿函数并且传递给内部的哈希桶,那么这里的代码就如下:

template<class K,class HashFunc=HashFunc<K>>
class UnorderedSet
{
    
    
public:
	struct KeyOfT
	{
    
    
		const K& operator()(const K& key)
		{
    
    
			return key;
		}
	};
private:
	BucketTable<K, K, KeyOfT, HashFunc> _ht;
};

#include"HashBucket.h"
template<class K, class T,class HashFunc = HashFunc<K>>
class UnorderedMap
{
    
    
public:
	struct KeyOfT
	{
    
    
		const K& operator()(const pair<K,T>& key)
		{
    
    
			return key.first;
		}
	};
private:
	BucketTable<K, pair<const K,T>, KeyOfT, HashFunc> _ht;
};

将基础的框架实现之后就可以完成内部的find函数,insert函数,erase函数,那么这里的实现原理就是通过调用哈希桶内部的函数来进行实现,那么这里的代码就如下:

template<class K,class HashFunc=HashFunc<K>>
class UnorderedSet
{
    
    
public:
	struct KeyOfT
	{
    
    
		const K& operator()(const K& key)
		{
    
    
			return key;
		}
	};
	bool insert(const K& key)
	{
    
    
		return _ht.insert(key);
	}
	bool erase(const K& key)
	{
    
    
		return _ht.erase(key);
	}
	HashNode<K>* find(const K& key)
	{
    
    
		return _ht.Find(key);
	}
private:
	BucketTable<K, K, KeyOfT, HashFunc> _ht;
};

template<class K, class T,class HashFunc = HashFunc<K>>
class UnorderedMap
{
    
    
public:
	struct KeyOfT
	{
    
    
		const K& operator()(const pair<K,T>& key)
		{
    
    
			return key.first;
		}
	};
	bool insert(const pair<K,T>& data)
	{
    
    
		return _ht.insert(data);
	}
	bool erase(const K& key)
	{
    
    
		return _ht.erase(key);
	}
	HashNode<K>* find(const K& key)
	{
    
    
		return _ht.Find(key);
	}
private:
	BucketTable<K, pair<const K,T>, KeyOfT, HashFunc> _ht;
};

有了这些基础的函数我们就可以用下面的代码来简单的检查一下上面的代码有没有实现正确,那么这里的检查代码就如下:

int main()
{
    
    
	UnorderedSet<int> set;
	int a[] = {
    
     18, 8, 7, 27, 57, 3, 38, 18 };
	for (auto e : a)
	{
    
    
		set.insert(e);
	}
	set.insert(17);
	set.insert(5);
	if (set.find(7)) {
    
     cout << "存在" << endl; }
	else {
    
     cout << "不存在" << endl; }
	set.erase(7);
	if (set.find(7)) {
    
     cout << "存在" << endl; }
	else {
    
     cout << "不存在" << endl; }
	return 0;
}

这段代码的运行结果如下:
在这里插入图片描述
运行的结果没有问题,那么这就说明我们上面实现的代码没有问题,接下来就可以继续实现map和set的迭代器。

迭代器的实现

哈希桶的每个节点都是一个链表,所以迭代器的遍历就是先从vector的第一个位置开始,先找到第一个节点不为空的位置,然后从上往下依次遍历链表中的每个节点,如果链表遍历完成之后就从当前位置完后继续寻找下一个vector中不为空的节点,那么这就是迭代器的实现思路,那么要想实现迭代器的++首先就得创建一个迭代器的类,
首先迭代器肯定得是一个模板,并且模板参数是四个,那么这里的代码就如下:

template<class K, class T, class KeyOfT, class Hash>
class _HashIterator
{
    
    

};

首先++函数肯定要记录HashNode节点,所以在该类里面就得创建一个节点指针,其次++函数的返回值是迭代器本身,所以这里可以用typedef简化一下该类,因为在++的时候需要使用vector容器来查找下一个链表的位置,所以这里就得把哈希桶类也传递过来,因为vector容器比较难传递所以这里就传递哈希桶,那么这里的代码就如下:

template<class K, class T, class KeyOfT, class Hash>
struct _HashIterator
{
    
    
	typedef HashNode<T> Node;
	typedef _HashIterator<K, T, KeyOfT, Hash> Self;
	typedef BucketTable<K, T, KeyOfT, Hash> Bt;
	Node* _node;
	Bt* _bt;
	Self& operatpr++()
	{
    
    
	}	
};

然后就来实现++的操作符重载,首先判断当前节点的下一个节点是否为空,如果不为空的话就说明下面还存在数据,我们就改变节点指针的指向,让其指向下一个节点,如果该节点的下一个指向为空的话,我们就得查找一个链表所在的位置,首先创建keyoft的仿函数找到数组中的key,然后通过hashfunc函数找到该数据转换的值,最后摸上容器的大小最终就可以确定当前元素所在的位置,然后就可以创建一个循环找到下一个不为空的位置,那么这里的代码就如下:

Self& operator++()
{
    
    
	if (_node->next)
	{
    
    
		//当前节点的下一个节点为空
		_node = _node->next;
	}
	else
	{
    
    
		KeyOfT kot;
		Hash hf;
		size_t hashi = hf(kot(_node->_data)) % _bt->_tables.size();
		++hashi;
		while (hashi < _bt->_tables.size())
		{
    
    
			if (_bt->_tables[hashi])
			{
    
    
				_node = _bt->_tables[hashi];
				break;
			}
			else
			{
    
    
				hashi++;
			}
		}

	}
}	

如果循环结束了这里会出现两种情况,第一种就是当前元素是最后一个元素再++就没有元素了,第二个情况就是找到了下一个元素,对于第一种情况就可以用hashi是否等于当前_tables.size()来进行判断,如果第一种情况不成立就说明当前情况是第二种情况,我们这里用迭代器的_node为空指针来代表当前已经来到了元素的最后一个位置,那么这里的代码就如下:

Self& operator++()
{
    
    
	if (_node->_next)
	{
    
    
		//当前节点的下一个节点不为空
		_node = _node->_next;
	}
	else
	{
    
    
		KeyOfT kot;
		Hash hf;
		size_t hashi = hf(kot(_node->_data)) % _bt->_tables.size();
		++hashi;
		while (hashi < _bt->_tables.size())
		{
    
    
			if (_bt->_tables[hashi])
			{
    
    
				_node = _bt->_tables[hashi];
				break;
			}
			else
			{
    
    
				hashi++;
			}
		}
		if (hashi == _bt->_tables.size())
		{
    
    
			_node = nullptr;
		}
	}
	return *this;
}

将这个实现完成之后就可以简单的实现一下操作符*和->的运算符重载,那么这里的代码就如下:

T& operator *()
{
    
    
	return _node->_data;
}
T* operator ->()
{
    
    
	return &_node->_data;
}
bool operator !=(const Self& s) const
{
    
    
	return _node != s._node;
}

这些函数实现完之后就可以来实现迭代器的构造函数,构造函数就是将节点指针和哈希桶指针初始化一下就可以了,那么这里的代码就如下:

_HashIterator(Node* node,Bt* bt)
	:_node(node)
	,_bt(bt)
{
    
    }

将这个函数完成之后我们就可以回到哈希桶的类然后接着实现迭代器对应的begin函数和end函数,这里的begin函数返回的就是vector容器中第一个链表不为空的地址,那么这里就可以创建一个for循环来不断地进行查找,那么这里地代码就如下:

typedef _HashIterator<K, T, KeyOfT, Hash> iterator;
iterator begin()
{
    
    
	for (int i = 0; i < _tables.size(); i++)
	{
    
    
		if (_tables[i])
		{
    
    
			return iterator(_tables[i], this);
		}
	}
}

end函数实现地原理也相似,但是我们使用nullptr来表示没有元素了,所以这里地代码实现如下:

iterator end()
{
    
    
	return iterator(nullptr, this);
}

但是我们这么实现存在一个问题,将代码运行一下便可以看到当前报出来了很多的错误:
在这里插入图片描述
原因是因为我们这里的实现的迭代器需要哈希桶,但是哈希桶的实现有需要迭代器,所以这里出现了相互引用自相矛盾了,所以这里就需要使用将哈希桶类前置声明的方式来解决问题,这里的代码如下:

template<class K, class T, class KeyOfT, class Hash >
class BucketTable;//前置声明

template<class K, class T, class KeyOfT, class Hash>
struct _HashIterator
{
    
    
	//....
}

将上面的代码实现之后就可以将这个迭代器套用到set里面

typedef typename BucketTable<K, K, KeyOfT, HashFunc>::iterator iterator;
iterator begin()
{
    
    
	return _ht.begin();
}
iterator end()
{
    
    
	return _ht.end();
}

将这个完成之后就可以用下面的代码来测试一下上面的正确性:

void test2()
{
    
    
	UnorderedSet<int> us;
	us.insert(1);
	us.insert(2);
	us.insert(3);
	us.insert(4);
	us.insert(5);
	UnorderedSet<int>::iterator it1 = us.begin();
	while (it1 != us.end())
	{
    
    
		cout << *it1 << endl;
		it1++;
	}
}

将这段代码运行一下就会发现上面的实现好像出了问题:
在这里插入图片描述
出现这个问题的原因就是
在这里插入图片描述
这里的_tables是一个私有的成员变量,迭代器类无法正常的访问,所以这里的解决方法就是使用友元来进行解决,那么这里的代码就如下:

template<class K, class T, class KeyOfT,class Hash >
class BucketTable
{
    
    
	template<class K, class T, class KeyOfT, class Hash>
	friend struct _HashIterator;
	//....
}

将这个完成之后就可以正常地运行上面地代码,那么这里运行地结果就如下:
在这里插入图片描述
将迭代器实现之后就可以将find函数地返回值和insert函数的返回值修改一下,insert返回的是pair,find返回的是iterator,这里修改之后就可以实现方括号的重载,方括号重载就是先调用insert函数,然后接收他的pair类型的返回值,最后返回pair元素的第一个的第二个元素,也就是Value,那么这里的代码就如下:

template<class K, class T,class HashFunc = HashFunc<K>>
class UnorderedMap
{
    
    
public:
	
	struct KeyOfT
	{
    
    
		const K& operator()(const pair<K,T>& key)
		{
    
    
			return key.first;
		}
	};
	typedef typename BucketTable<K, pair<const K,T>, KeyOfT, HashFunc>::iterator iterator;
	iterator begin()
	{
    
    
		return _ht.begin();
	}
	iterator end()
	{
    
    
		return _ht.end();
	}
	pair<iterator,bool> insert(const pair<K,T>& data)
	{
    
    
		return _ht.insert(data);
	}
	bool erase(const K& key)
	{
    
    
		return _ht.erase(key);
	}
	iterator find(const K& key)
	{
    
    
		return _ht.Find(key);
	}
	T& operator[](const K& key)
	{
    
    
		pair<iterator, bool> ret = _ht.insert(make_pair(key, T()));
		return ret.first->second;
	}
private:
	BucketTable<K, pair<const K,T>, KeyOfT, HashFunc> _ht;
};

这里可以使用下面的代码来进行一下测试:

void test3()
{
    
    
	string arr[] = {
    
     "苹果", "西瓜", "香蕉", "草莓", "苹果", "西瓜", 
		"苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
		
	UnorderedMap<string, int> countMap;
	for (auto& e : arr)
	{
    
    
		countMap[e]++;
	}
	for (const auto& kv : countMap)
	{
    
    
		cout << kv.first << ":" << kv.second << endl;
	}
}

代码的运行结果如下:
在这里插入图片描述
代码的运行结果符合我们的预期,那么接下来我们就来看看const迭代器是如何实现的。

const迭代器

根绝前面的经验我们知道可以通过添加模板参数的形式来将const迭代器和普通迭代器融合在一起,那么首先将迭代器的模板参数进行修改,并且将两个操作符的解引用进行修改,就可以得到下面的代码:

template<class K, class T,class Ref,class Ptr, class KeyOfT, class Hash>
struct _HashIterator
{
    
    
	typedef HashNode<T> Node;
	typedef _HashIterator<K, T, Ref,Ptr,KeyOfT, Hash> Self;
	typedef BucketTable<K, T, KeyOfT, Hash> Bt;
		Node* _node;
	Bt* _bt;
	_HashIterator(Node* node,Bt* bt)
		:_node(node)
		,_bt(bt)
	{
    
    }
	Self& operator++()
	{
    
    //....return *this;}	
	Ref operator *()
	{
    
    return _node->_data;}
	Ptr operator ->()
	{
    
    return &_node->_data;}
	bool operator !=(const Self& s) const
	{
    
    return _node != s._node;}
};

然后就对哈希桶类中的代码进行修改,创建一个const迭代器,增加const版本的begin函数和end函数,那么这里的代码大致如下:

template<class K, class T, class KeyOfT,class Hash >
class BucketTable
{
    
    
public:
	typedef HashNode<T> Node;
	template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
	friend struct _HashIterator;
	BucketTable()
		:_n(0)
	{
    
    
		_tables.resize(__stl_next_prime(_tables.size()));
	}
	typedef _HashIterator<K, T, T&, T*, KeyOfT, Hash> iterator;
	typedef _HashIterator<K, T,const T&,const T* ,KeyOfT, Hash> const_iterator;
	iterator begin()
	{
    
    //...}
	iterator end()
	{
    
    //...}
	const_iterator begin() const
	{
    
    //...}
	const_iterator end() const 
	{
    
    //...}
	iterator Find(const K& key)
	{
    
    //...}
	bool erase(const K& key)
	{
    
    //...}
	~BucketTable()
	{
    
    //...}
	inline unsigned long __stl_next_prime(unsigned long n)
	{
    
    //...}
private:
	vector<Node*> _tables;
	size_t _n;
};

然后就可以用下面的代码来进行一下测试:

void test4(const UnorderedSet<int>& us)
{
    
    
	UnorderedSet<int>::const_iterator it = us.begin();
	while (it != us.end())
	{
    
    
		cout << *it << endl;
		it++;
	}
	cout << endl;
}
int main()
{
    
    
	UnorderedSet<int> us;
	us.insert(1);
	us.insert(2);
	us.insert(3);
	us.insert(4);
	test4(us);
	return 0;
}

这段代码的运行结果如下:
在这里插入图片描述

我们发现上面的这种实现方法出现了问题,出问题的地方就在构造函数,我们使用begin函数来创建const迭代器,因为us被const所修饰所以这里调用的begin是const类型的begin

const_iterator begin() const
{
    
    
	for (int i = 0; i < _tables.size(); i++)
	{
    
    
		if (_tables[i])
		{
    
    
			return const_iterator(_tables[i], this);
		}
	}
}

这里的begin函数是通过找到第一个不为空的节点来构造const迭代器,因为这里是const版本,所以这里使用的_tables[i]也是const版本,_tables是一个vector容器并且还是const版本,这里调用方括号的返回值来进行构造,而vector的方括号重载也分为两个版本:
在这里插入图片描述
所以这里返回的就是const版本的,而迭代器在构造的时候是使用普通版本的指针来进行构造:

_HashIterator(Node* node,Bt* bt)
		:_node(node)
		,_bt(bt)
	{
    
    }

所以这里的迭代器对象创建就失败了,如果给这里的node指针添加const的话依然是无法解决问题的,他会报出下面的错误:

_HashIterator( const Node* node,const Bt* bt)
		:_node(node)
		,_bt(bt)
	{
    
    }

在这里插入图片描述

因为这里的权限被放大了,所以就出现问题,那如果我们讲_node也变成const属性呢?比如说下面这样:

const Node* _node;
const Bt* _bt;
_HashIterator(const Node* node,Bt* bt)
	:_node(node)
	,_bt(bt)
{
    
    }

如果这样的话那普通迭代器还能对里面的内容进行修改吗?是不是就不行了啊,所以这里采用的解决方法就是const迭代器和普通迭代器分开定义,比如说下面的代码:

template<class K, class T, class KeyOfT, class Hash>
struct const_HashIterator
{
    
    
	typedef HashNode<T> Node;
	typedef const_HashIterator<K, T, KeyOfT, Hash> Self;
	typedef BucketTable<K, T, KeyOfT, Hash> Bt;
	const Node* _node;
	const Bt* _bt;
	const_HashIterator(const Node* node, const Bt* bt)
		:_node(node)
		, _bt(bt)
	{
    
    }
	Self& operator++()
	{
    
    }
	const T& operator *()
	{
    
    }
	const T* operator ->()
	{
    
    }
	bool operator !=(const Self& s) const
	{
    
    }
};

这样我们再运行上面的代码就不会出现问题:
在这里插入图片描述
那么到这里本篇文章的内容就全部完成了,所有的代码如下:

//哈希桶文件的代码
#pragma once
#include<iostream>
#include<vector>
using namespace std;
template< class T>
struct HashNode
{
    
    
	HashNode(const T& data)
		:_data(data)
		, _next(nullptr)
	{
    
    }
	T _data;
	HashNode<T>* _next;
};
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)
	{
    
    
		size_t res = 0;
		for (auto& ch : s)
		{
    
    
			res *= 131;
			res += ch;
		}
		return res;
	}
};
template<class K, class T, class KeyOfT, class Hash >
class BucketTable;//前置声明

template<class K, class T, class KeyOfT, class Hash>
struct const_HashIterator
{
    
    
	typedef HashNode<T> Node;
	typedef const_HashIterator<K, T, KeyOfT, Hash> Self;
	typedef BucketTable<K, T, KeyOfT, Hash> Bt;
	const Node* _node;
	const Bt* _bt;
	const_HashIterator(const Node* node, const Bt* bt)
		:_node(node)
		, _bt(bt)
	{
    
    }
	Self& operator++()
	{
    
    
		if (_node->_next)
		{
    
    
			//当前节点的下一个节点为空
			_node = _node->_next;
		}
		else
		{
    
    
			KeyOfT kot;
			Hash hf;
			size_t hashi = hf(kot(_node->_data)) % _bt->_tables.size();
			++hashi;
			while (hashi < _bt->_tables.size())
			{
    
    
				if (_bt->_tables[hashi])
				{
    
    
					_node = _bt->_tables[hashi];
					break;
				}
				else
				{
    
    
					hashi++;
				}
			}
			if (hashi == _bt->_tables.size())
			{
    
    
				_node = nullptr;
			}
		}
		return *this;
	}
	const T& operator *()
	{
    
    
		return _node->_data;
	}
	const T* operator ->()
	{
    
    
		return &_node->_data;
	}
	bool operator !=(const Self& s) const
	{
    
    
		return _node != s._node;
	}
};

template<class K, class T, class KeyOfT, class Hash>
struct _HashIterator
{
    
    
	typedef HashNode<T> Node;
	typedef _HashIterator<K, T,KeyOfT, Hash> Self;
	typedef BucketTable<K, T, KeyOfT, Hash> Bt;
	Node* _node;
	Bt* _bt;
	_HashIterator( Node* node,Bt* bt)
		:_node(node)
		,_bt(bt)
	{
    
    }
	Self& operator++()
	{
    
    
		if (_node->_next)
		{
    
    
			//当前节点的下一个节点为空
			_node = _node->_next;
		}
		else
		{
    
    
			KeyOfT kot;
			Hash hf;
			size_t hashi = hf(kot(_node->_data)) % _bt->_tables.size();
			++hashi;
			while (hashi < _bt->_tables.size())
			{
    
    
				if (_bt->_tables[hashi])
				{
    
    
					_node = _bt->_tables[hashi];
					break;
				}
				else
				{
    
    
					hashi++;
				}
			}
			if (hashi == _bt->_tables.size())
			{
    
    
				_node = nullptr;
			}
		}
		return *this;
	}	
	T& operator *()
	{
    
    
		return _node->_data;
	}
	T* operator ->()
	{
    
    
		return &_node->_data;
	}
	bool operator !=(const Self& s) const
	{
    
    
		return _node != s._node;
	}
};
template<class K, class T, class KeyOfT,class Hash >
class BucketTable
{
    
    
public:	
	typedef HashNode<T> Node;
	template<class K, class T, class KeyOfT, class Hash>
	friend struct _HashIterator;

	template<class K, class T, class KeyOfT, class Hash>
	friend struct const_HashIterator;
	BucketTable()
		:_n(0)
	{
    
    
		_tables.resize(__stl_next_prime(_tables.size()));
	}
	typedef _HashIterator<K, T, KeyOfT, Hash> iterator;
	typedef const_HashIterator<K, T,KeyOfT, Hash> const_iterator;
	iterator begin()
	{
    
    
		for (int i = 0; i < _tables.size(); i++)
		{
    
    
			if (_tables[i])
			{
    
    
				return iterator(_tables[i], this);
			}
		}
	}
	iterator end()
	{
    
    
		return iterator(nullptr, this);
	}
	const_iterator begin() const
	{
    
    
		for (int i = 0; i < _tables.size(); i++)
		{
    
    
			if (_tables[i])
			{
    
    
				return const_iterator(_tables[i], this);
			}
		}
	}
	const_iterator end() const 
	{
    
    
		const_iterator it1(nullptr, this);
		return it1;
	}
	iterator Find(const K& key)
	{
    
    
		Hash hf;
		size_t pos = hf(key) % _tables.size();
		KeyOfT kot;
		Node* cur = _tables[pos];
		while (cur)
		{
    
    
			if (kot(cur->_data) == key)
			{
    
    
				return iterator(cur,this);
			}
			else
			{
    
    
				cur = cur->_next;
			}
		}
		return iterator(nullptr,this);
	}
	pair<iterator,bool> insert(const T& data)
	{
    
    
		KeyOfT kot;
		iterator it = Find(kot(data));
		if (it!=end())
		{
    
    
			return make_pair(it,false);
		}
		if (_n / _tables.size() == 1)//平衡因子为1就更新
		{
    
    
			vector<Node*> newBH;
			newBH.resize(__stl_next_prime(_tables.size()));
			for (int i = 0; i < _tables.size(); i++)
			{
    
    
				Node* cur = _tables[i];
				while (cur)
				{
    
    
					Node* next = cur->_next;
					size_t pos = Hash()(kot(cur->_data));
					cur->_next = newBH[pos];
					newBH[pos] = cur;
					cur = next;
				}
				_tables[i] = nullptr;
			}
		}
		Hash hf;
		size_t pos = hf(kot(data)) % _tables.size();
		Node* newnode = new HashNode< T>(data);
		newnode->_next = _tables[pos];
		_tables[pos] = newnode;
		++_n;
		return make_pair(iterator(newnode,this),true) ;
	}
	bool erase(const K& key)
	{
    
    
		HashFunc<K> HF;
		KeyOfT kot;
		size_t pos = HF(key) % _tables.size();
		Node* cur = _tables[pos];
		Node* prev = cur;
		while (cur)
		{
    
    
			if (kot(cur->_data) == key)
			{
    
    
				if (cur == _tables[pos])
				{
    
    
					_tables[pos] = cur->_next;
				}
				else
				{
    
    
					prev->_next = cur->_next;
				}
				delete cur;
				_n--;
				return true;
			}
			else
			{
    
    
				prev = cur;
				cur = cur->_next;
			}
		}
		return false;
	}
	~BucketTable()
	{
    
    
		for (int i = 0; i < _tables.size(); i++)
		{
    
    
			Node* cur = _tables[i];
			while (cur)
			{
    
    
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
			_tables[i] = nullptr;
		}
	}
	inline unsigned long __stl_next_prime(unsigned long n)
	{
    
    
		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
		};
		for (int i = 0; i < __stl_num_primes; ++i)
		{
    
    
			if (__stl_prime_list[i] > n)
			{
    
    
				return __stl_prime_list[i];
			}
		}
		return __stl_prime_list[__stl_num_primes - 1];
	}


private:
	vector<Node*> _tables;
	size_t _n;
};
//封装的set的代码
#include"HashBucket.h"

template<class K,class HashFunc=HashFunc<K>>
class UnorderedSet
{
    
    
public:
	
	struct SetOfT
	{
    
    
		const K& operator()(const K& key)
		{
    
    
			return key;
		}
	};
	typedef typename BucketTable<K, K, SetOfT, HashFunc>::iterator iterator;
	typedef typename BucketTable<K, K, SetOfT, HashFunc>::const_iterator 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);
	}
	bool erase(const K& key)
	{
    
    
		return _ht.erase(key);
	}
	iterator find(const K& key)
	{
    
    
		return _ht.Find(key);
	}
private:
	BucketTable<K, K, SetOfT, HashFunc> _ht;
};
//封装的map的代码
#include"HashBucket.h"
template<class K, class T,class HashFunc = HashFunc<K>>
class UnorderMap
{
    
    
public:
	
	struct MapOfT
	{
    
    
		const K& operator()(const pair<const K,T>& key)
		{
    
    
			return key.first;
		}
	};
	typedef typename BucketTable<K, pair<const K,T>, MapOfT, HashFunc>::iterator iterator;
	typedef typename BucketTable<K, K, MapOfT, HashFunc>::const_iterator 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 pair< const K,T>& data)
	{
    
    
		return _ht.insert(data);
	}
	bool erase(const K& key)
	{
    
    
		return _ht.erase(key);
	}
	iterator find(const K& key)
	{
    
    
		return _ht.Find(key);
	}
	T& operator[](const K& key)
	{
    
    
		pair<iterator, bool> ret = _ht.insert(make_pair(key, T()));
		return ret.first->second;
	}
private:
	BucketTable<K, pair<const K,T>, MapOfT, HashFunc> _ht;
};

猜你喜欢

转载自blog.csdn.net/qq_68695298/article/details/131464716