在前边的博客中我们已经实现了哈希表,我们又知道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;
};