数据结构哈希表--线性探测和哈希桶及unordered_set,unordered_map代码示范

Posted zhao111222333444

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构哈希表--线性探测和哈希桶及unordered_set,unordered_map代码示范相关的知识,希望对你有一定的参考价值。

这里写目录标题

哈希桶

#include<iostream>
#include<vector>
using namespace std;
//开散列

//hash表封装了一个链表指针数组,和一个size(存放的元素个数)
//链表指针数组里面就是单链表的节点

//单链表节点
template<class V>
struct HashNode
	V _val;
	HashNode<V>* _next;

	//再写一个构造函数,插入等操作需要在某位置新建节点
	HashNode(const V& val)
		:_val(val)//可能是K,也可能是pair<K,v>
		, _next(nullptr)
	

;


//在实现了hashtable后,需要实现迭代器
//哈希表的迭代器需要封装链表节点
//由于hashtable的具体结构不确定,我们还需要一个hashtable来辅助迭代器的实现
//这时就有一个问题,iterator需要hashtable,hashtable需要iterator,这时就需要前置声明和友元来解决
template<class K, class V, class KeyOfValue, class HashFun=HashFun<K>>
class HashTable;

//迭代器的实现:
template<class K, class V, class KeyOfValue, class HashFun = HashFun<K>>
struct Hashiterator
	//成员:哈希表指针,节点指针
	typedef Hashiterator<K, V, KeyOfValue,  HashFun> Self;
	typedef HashTable<K, V, KeyOfValue,  HashFun> HT;
	typedef HashNode<V> Node;
	Node* _node;
	HT* _hptr;

	//迭代器的构造函数
	Hashiterator(Node* node, HT* hptr)
		:_node(node)
		, _hptr(hptr)
	

	V& operator*()
		return _node->_val;
	

	V* operator->()
		return &_node->_val;//返回??
	

	bool operator!=(const Self& it)
		return _node != it._node;
	

	//迭代器的++需要考虑2种情况
	//1.链表有next
	//2.没有next
	Self& operator++()
		if (_node->_next)
			_node = _node->_next;
		
		else
			//查找下一个非空链表的头结点

			//先找出该节点的hash位置,再向后查找
			KeyOfValue kov;
			HashFun hfun;
			//这里想要使用哈希表指针指向的指针数组的私有成员_ht,需要在hashtable里友元迭代器类
			size_t idx = hfun(kov(_node->_val)) % _hptr->_ht.size();
			++idx;
			for (; idx < _hptr->_ht.size(); ++idx)//需要遍历后续链表头节点
				if (_hptr->_ht[idx])//如果哈希表的vector对应的索引存在就找到
					_node = _hptr->_ht[idx];
					break;
				
			
			//没有找到的情况
			if (idx == _hptr->_ht.size())//和vector的长度比,不可和实际元素个数比
				_node = nullptr;
			
		
		return *this;
	

;


//接下来是哈希表的实现
//kov是用来获取节点val的K值的
template<class K,class V,class KeyOfValue,class HashFun>
class HashTable

public:
	typedef HashNode<V> Node;
	typedef Hashiterator<K, V, KeyOfValue,  HashFun> iterator;

	//友元
	template<class K, class V, class KeyOfValue, class HashFun>
	friend struct Hashiterator;


	//构造函数(可以写个缺省值创建vector)
	HashTable(int n = 10)
		:_ht(n)
		, _size(0)
	

	//写出迭代器
	iterator begin()
		for (size_t i = 0; i < _ht.size(); ++i)
			if (_ht[i])
				return iterator(_ht[i], this);//谁调用迭代器就用那个哈希表创建迭代器
			
		
		return iterator(nullptr, this);
	

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


	pair<iterator, bool> insert(const V& val)
	//bool insert(const V& val)
		//0.检查容量
		checkCapacity();
		//1.计算哈希位置

		//需要用k值查找,所以用kov
		KeyOfValue kov;
		HashFun hfun;
		int idx = hfun(kov(val)) % _ht.size();

		//2.检查是否存在

		Node* cur = _ht[idx];
		while (cur)
			if (kov(cur->_val) == kov(val))//如果节点的val(的K)相等
				return make_pair(iterator(cur, this), false);
				//return false;
			
			cur = cur->_next;
		
		//3.插入指针数组(头插)
		cur = new Node(val);
		cur->_next = _ht[idx];
		_ht[idx] = cur;
		++_size;
		return make_pair(iterator(cur, this), true);
		//return true;

	

	size_t GetNextPrime(size_t prime)
	
		const int PRIMECOUNT = 28;
		const size_t primeList[PRIMECOUNT] =
		
			53ul, 97ul, 193ul, 389ul, 769ul,
			1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
			49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
			1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
			50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
			1610612741ul, 3221225473ul, 4294967291ul
		;
		size_t i = 0;
		for (; i < PRIMECOUNT; ++i)
		
			if (primeList[i] > primeList[i])
				return primeList[i];
		
		return primeList[i];
	

	void checkCapacity()
		if (_size == _ht.size())//如果实际的数据和指针数组的长度相同需要扩容
			//计算容量大小
			int newc = _size == 0 ? 10 : 2 * _size;
			//开辟空间
			vector<Node*> newht(newc);

			KeyOfValue kov;
			HashFun hfun;
			//遍历旧表插入新表
			for (size_t i = 0; i < _ht.size(); ++i)
			//for用来遍历指针数组的链表头节点
				Node* cur = _ht[i];
			//while遍历链表
				while (cur)
					//需要记录下一个位置,因为我们是修改指针的指向,下一个不存会丢失
					Node* next = cur->_next;
					//计算新的表的hash位置
					int idx = hfun(kov(cur->_val)) % newht.size();

					//头插
					cur->_next = newht[idx];
					newht[idx] = cur;

					cur=next;
				

				//需要将旧表置空
				_ht[i] = nullptr;
			

			//交换表,旧表就跟着vector的析构函数销毁了
			swap(_ht, newht);
		
	
		 

	Node* Find(const K& key)
		KeyOfValue kov;
		HashFun hfun;
		int idx = key % _ht.size();

		//2.检查是否存在

		Node* cur = _ht[idx];
		while (cur)
			if hfun((kov(cur->_val)) == key)//如果节点的val(的K)相等
				return cur;
			
			cur = cur->_next;
		
		return nullptr;
	


	bool Erase(const K& key)
		KeyOfValue kov;
		HashFun hfun;
		int idx = key % _ht.size();
		Node* cur = _ht[idx];
		if (!cur)
			return false;
		
		else if (cur->_next == nullptr)
			delete cur;
			_ht[idx] = nullptr;
			return true;
		
		else
			Node* prev = cur;
			cur = cur->_next;
			while (cur)
				if (hfun(kov(cur->_val)) == key)
					Node* tmp = cur;
					cur = cur->_next;
					prev->_next = tmp->_next;
					return true;
				
			

		
		return false;
	
		//X开散列删除
		/*Node* prev = nullptr;
		
		Node* pret = nullptr;
		while (cur)
			
			if (kov(cur->_val) == key )//如果节点的val(的K)相等
				//Node* next = cur->_next;
				//prev = cur;
				if (cur == _ht[idx])
					_ht[idx] = cur->_next;
				else
					prev->_next = cur->_next;
				delete cur;
				--_size;
			
			cur = cur->_next;
			
		
		return nullptr;*/

	



private:
	vector<Node*> _ht;
	int _size;


;

//哈希函数
template <class K>
struct Hashfun
	size_t operator()(const K& key)
		return key;
	

;


//将字符串转数字的哈希函数
struct Hashfunstring

	size_t operator()(const string& key)
		size_t hash = 0;
		for (const auto& ch : key)
			hash = hash * 131 + ch;
		
		return hash;
	
;

//也可以这样写
template<>
struct Hashfun<string>

	size_t operator()(const string& key)
		size_t hash = 0;
		for (const auto& ch : key)
			hash = hash * 131 + ch;
		
		return hash;
	
;



//自定义类型的哈希函数示例:
class A
public:
	int _a;
	string _b;
	double _d;
	//自定义类型需要手写==运算符重载
	bool operator==(const A& a)
		return _a == a._a && _b == a._b && _d == a._d;
	
;

struct HashfunA
	size_t operator()(const A& a)
		return a._a ;
	

;
template <class K>
struct HashFun

	size_t operator()(const K& key)
		return key;
	
;

map和set






//因为我的hashfun给了缺省,so这里可以不写
//哈希表底层的map实现
//map底层的哈希表的指针数组放的是,成员为pair的单链表指针
template <class K,class V>
class Map
	//因为哈希表是三个泛型,第三个为获取K的仿函数
	struct MapKeyOfValue
	
		//仅需要重载()运算符即可获取K值
		const K& operator()(const pair<K, V>& val)
			return val.first;
		
	;

public:
	typedef typename HashTable<K, pair<K, V>, MapKeyOfValue>::iterator iterator;

	pair<iterator, bool> insert(const pair<K, V>& val)
		return _ht.insert(val);
	

	iterator begin()
		return _ht.begin();
	

	iterator end()
		return _ht.end();
	

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

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

private:
	HashTable<K, pair<K, V>, MapKeyOfValue> _ht;

;


template <class K>
class Set
	//因为哈希表是三个泛型,第三个为获取K的仿函数
	struct SetKeyOfValue
	
		//仅需要重载()运算符即可获取K值
		const K& operator()(const K& val)
			return val;
		
	;

public:
	typedef typename HashTable<K, K, SetKeyOfValue>::iterator iterator;

	pair<iterator, bool> insert(const K& val)
		return _ht.insert(val);
	

	iterator begin()
		return _ht.begin();
	

	iterator end()
		return _ht.end();
	


	bool earse(const K& val)
		return _ht.Erase(val);
	

private:
	HashTable<K, K, SetKeyOfValue> _ht;

;

void test()
	/*Set<int> s;
	s.insert(1);
	s.insert(11);
	s.insert(12);
	s.insert(13);
	s.insert(44);
	s.insert(5);
	s.insert(7);
	s.insert(8);
	s.insert(2);
	s.insert(3);
	s.earse(1);
	s.earse(11);
	s.earse(12);
	s.earse(100);*/
	Map<int, int> s;
	s.insert(make_pair(1, 1));
	s[1] = 5;
	s[5] = 10;
	s[15] = 15;
	s[4] = 4;
	s.earse(1);
	//cout << s.find(2) << endl;
	for (auto& e : s)
		cout << e.first << " " << e.second << endl;
	

int main()
	test();
	system("pause");
	return 0;

线性探测

#include<vector>
#include<iostream>
using namespace std;
//闭散列主要是线性探测
//每一个节点是一种标志位和一个值
//哈希表里面是一个节点的vector和有效元素个数
enum STATE

	EXIST,
	DELETE,
	EMPTY
;


//我们让节点里存放kv键值对
template<class K, class V>
struct HashNode

	pair<K, V> _kv;
	STATE _state = EMPTY;
;


//哈希表的实现:
template<class K, class V>
class HashTable

public:
	typedef HashNode<K, V> Node;
	
	HashTable(size_t n C++数据结构——哈希表

C++数据结构——哈希表

C++数据结构——哈希表

C++数据结构——哈希表

手撕STLunordered_setunordered_map(用哈希表封装)

哈希表底层探索