【C++】哈希封装unordered_map和unordered_set

本文介绍了如何自定义哈希表,以模板形式封装unordered_map和unordered_set,包括使用哈希节点、迭代器的设计,以及处理扩容逻辑,减少内存消耗。
摘要由CSDN通过智能技术生成

在前边的博客中我们已经实现了哈希表,我们又知道unordered_map和unordered_set就是用哈希表封装出来的,那么我们就自己来封装出它们,就跟之前用红黑树封装出set和map是一样的,我们这里使用哈希桶的版本

首先我们要用一个哈希表同时实现map和set,一个是key结构,一个是keyvalue结构,这就要求我们把哈希节点设置成模板T

map和set分别传不同的类型

下一个要实现的就是我们的迭代器,迭代器就是去遍历元素的,要找到一个元素需要哪些东西呢?我们这里可以用哈希表,第几个位置和指针来确定。但其实有了指针,我们再找到对应的值,就可以利用哈希函数计算出位置,所以只需要两个成员变量就可以了

因为我们的迭代器用到了哈希表,而哈希表有用到了迭代器,所以谁先谁后无法解决矛盾,所以我们选择在迭代器前加上哈希表的声明

并且呢,我们让哈希表作为迭代器的成员变量,多次用到了哈希表的私有成员,所以要迭代器是哈希表的友元,下面这个是写在哈希表里面的

下面还有一个点我们再实现哈希桶的时候没有说,就是我们的扩容逻辑,我们要扩容就意味着要把旧表中所有节点再计算一遍位置放到新表中,而我们这节点都是new出来的,如果delete掉再new一遍太浪费了,所以我们直接把就表中的节点挂到新表中就可以了。但还有一个关键的点就是要将旧表中的值置为空否则就会析构两遍!!!

下面是三个头文件中的所有代码

Hash_tables.h

#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;

template<class T>//哈希函数的模板
struct hashfun {
	size_t operator()(const T& key) {
		return (size_t)key;
	}
};
template<>//string用的多,进行了特化处理
struct hashfun<string> {
	size_t operator()(const string& str) {
		size_t hashret = 0;
		for (auto& e : str) {
			hashret = hashret * 131 + e;
		}
		return hashret;
	}
};
namespace hash_bucket {

	template<class T>//哈希节点
	struct HashNode {
		HashNode(const T&vall)
			:val(vall)
			,_next(nullptr){}

		T val;
		HashNode<T>* _next = nullptr;
	};

	template<class K, class V, class kov, class hashfunc>//迭代器要用到哈希表,加一个前置声明
	class HashTable;

	template<class K, class V, class kov, class hashfunc = hashfun<K>>
	struct HashIterator {
		typedef HashNode<V> Node;
		typedef HashTable<K, V, kov, hashfunc> HT;
		typedef HashIterator<K, V, kov, hashfunc> self;
		HashIterator(HT* htptr, Node* ptr)
			:_htptr(htptr)
			, _ptr(ptr) {}

		self& operator++() {
			if (_ptr->_next) {
				_ptr = _ptr->_next;
				return *this;
			}
			else {
				int pos = hashfunc()(kov()(_ptr->val))% _htptr->_hashvec.size();
				for (size_t i = pos + 1; i < _htptr->_hashvec.size(); i++) {
					if (_htptr->_hashvec[i]) {
						_ptr = _htptr->_hashvec[i];
						return *this;
					}
				}
			}
			_ptr = nullptr;
			return *this;
		}
		bool operator!=(const self& it1) {
			return this->_ptr != it1._ptr;
		}
		V& operator*() {
			if (this->_ptr == nullptr)assert(false);
			return this->_ptr->val;
		}

		V* operator->() {
			return &(this->_ptr->val);
		}
		HT* _htptr;
		Node* _ptr;
	};

	template<class K, class V, class kov, class hashfunc = hashfun<K>>
	class HashTable {
		typedef HashNode<V> Node;
	public:

		typedef HashIterator<K, V, kov, hashfunc> iterator;

		//friend struct HashIterator<K, V, kov, hashfunc>;声明友元类的两种方式
		template<class K, class V, class kov, class hashfunc >
		friend struct HashIterator;

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

		iterator begin() {
			for (size_t i = 0; i < _hashvec.size(); i++) {
				if (_hashvec[i])return iterator(this, _hashvec[i]);
			}
			return end();
		}
		iterator end() {
			return iterator(this, nullptr);
		}
		iterator find(const K& key) {
			kov Kov;
			size_t hashi = hashfunc()(key) % _hashvec.size();
			Node* cur = _hashvec[hashi];
			while (cur) {
				if (Kov(cur->val) == key)return iterator(this, cur);
				cur = cur->_next;
			}
			return end();
		}
		pair<iterator, bool> insert(const V& _kv) {
			kov Kov;
			if (find(Kov(_kv)) != end())return pair<iterator, bool>(find(Kov(_kv)), false);
			if (_n == _hashvec.size()) {//负载因子到一就扩容
				//扩容
				HashTable newtable(_hashvec.size() * 2);
				for (size_t i = 0; i < _hashvec.size(); i++) {
					Node* cur = _hashvec[i];
					Node* next = nullptr;

					while (cur) {
						next = cur->_next;
						size_t hashi = hashfunc()(Kov(cur->val)) % newtable._hashvec.size();
						cur->_next = newtable._hashvec[hashi];//头插
						newtable._hashvec[hashi] = cur;
						cur = next;
					}
					_hashvec[i] = nullptr;//原来的vector要成为空节点,防止以后析构两次
				}
				_hashvec.swap(newtable._hashvec);
			}
			size_t hashi = hashfunc()(Kov(_kv)) % _hashvec.size();
			Node* newnode = new Node(_kv);
			newnode->_next = _hashvec[hashi];
			_hashvec[hashi] = newnode;
			++_n;
			return make_pair(iterator(this,  newnode), true);
		}


		bool erase(const K& key) {
			kov Kov;
			size_t hashi = hashfunc()(key) % _hashvec.size();
			Node* prev = nullptr;
			Node* cur = _hashvec[hashi];
			while (cur && (Kov(cur->val)) != key) {
				prev = cur;
				cur = cur->_next;
			}
			if (cur == nullptr)return false;
			if (prev == nullptr) {
				_hashvec[hashi] = cur->_next;
			}
			else {
				prev->_next = cur->_next;
			}
			delete cur;
			return true;
		}
	private:
		size_t _n = 0;
		vector<Node*> _hashvec;
	};
}

Myunordered_map.h

#include"Hash_tables.h"
template<class K,class V>
struct mapkov {
	const K& operator()(const pair<K,V>&_kv) {
		return _kv.first;
	}
};

template<class K,class V, class hashfunc = hashfun<K>>
class unordered_map {
public:
	typedef typename hash_bucket::HashTable<K, pair<K, V>, mapkov<K, V>>::iterator iterator;
	bool insert(const pair<K,V>& kv) {
		return ht.insert(kv).second;
	}
	bool erase(const K& key) {
		return ht.erase(key);
	}
	iterator find(const K& key) {
		return ht.find(key);
	}
	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;
	}
	
private:
	hash_bucket::HashTable<K, pair<K,V>,mapkov<K,V>>ht;
};

Myunordered_set.h

#include"Hash_tables.h"
template<class K>
struct setkov {
	const K& operator()(const K&key) {
		return key;
	}
};

template<class K,class hashfunc=hashfun<K>>
class unordered_set {
public:
	typedef typename hash_bucket::HashTable<K,K, setkov<K>>::iterator iterator;

	bool insert(const K& key) {
		return ht.insert(key).second;
	}
	bool erase(const K& key) {
		return ht.erase(key);
	}
	iterator begin() {
		return ht.begin();
	}
	iterator end() {
		return ht.end();
	}
	iterator find(const K& key) {
		return ht.find(key);
	}
private:
	hash_bucket::HashTable<K, K,setkov<K>>ht;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值