当前位置: 首页 > news >正文

用哈希表封装unordered_set和unordered_map

用哈希表封装unordered_set和unordered_map

  • 1. 实现哈希表
  • 2. 封装unordered_map和unordered_set框架,解决KeyOfT
    • 2.1 封装unordered_map和unordered_set框架
    • 2.2 解决KeyOfT
  • 3. iterator
    • 3.1 哈希表的迭代器的框架
    • 3.2 解决前置++、begin()、end()
    • 3.3 测试begin()、end()、前置++
  • 4. const_iterator
  • 5. key不支持修改的问题
  • 6. operator[]
  • 7. 所有的实现代码
    • unordered_set.h
    • unordered_map.h
    • HashTable.h
    • test.cpp

1. 实现哈希表

红黑树的实现已经在unordered_map和unordered_set的使用以及哈希表的实现详细讲解,这里不再说明。

2. 封装unordered_map和unordered_set框架,解决KeyOfT

2.1 封装unordered_map和unordered_set框架

  1. 因为哈希表底层不知道你传过来的到底是K,还是pair<K, V>,所以哈希表的节点把类型统一改为泛型T代替。我会标记一下修改的代码。
  2. 哈希表的两个模板参数的作用:第一个模板参数K:它是为了find只传一个key值做准备;第二个模板参数T:它就是节点数据类型。
  3. 可以发现如果传泛型T,在进行取模的时候是不知道怎么取模的,对于unordered_set直接取模就行了,因为它传的是K,对于unordered_map就要用pair的first去取模了,所以下一步就是要解决KeyOfT问题,就是要取出T中的Key。
// HashTable.h
namespace hash_bucket
{template<class T> // 修改struct HashNode{T _data; // 修改HashNode<T>* _next; // 修改HashNode(const T& data) // 修改:_data(data),_next(nullptr){}};template<class K, class T, class Hash = HashFunc<K>> // 修改class HashTable{typedef HashNode<T> Node; // 修改public://...bool Insert(const T& data) // 修改{//...Node* newnode = new Node(data); // 修改// 头插newnode->_next = _tables[hashi];_tables[hashi] = newnode; ++_n;return true;}

下面是unordered_map和unordered_set的准备工作:
unordered_map和unordered_set的成员变量的类型是一个哈希表,unordered_map和unordered_set属于上层,unordered_map知道第二个参数传pair<K, V>,unordered_set知道第二个参数传K。

//unordered_set.h
#pragma once#include "HashTable.h"namespace bs
{template<class K>class unordered_set{private:hash_bucket::HashTable<K, K> _ht;};
}// unordered_map.h
#pragma once#include "HashTable.h"namespace bs
{template<class K, class V>class unordered_map{private:hash_bucket::HashTable<K, pair<K, V>> _ht;};
}

2.2 解决KeyOfT

为了解决key值取模的问题,我们新增了一个模板参数KeyOfT;它存在的意义就是从T中取出key值,进行取模。

//HashTable.h
template<class K, class T, class KeyOfT, class Hash = HashFunc<K>> // 修改
class HashTable
{typedef HashNode<T> Node;
public://...bool Insert(const T& data){KeyOfT kot; // 修改if (Find(kot(data))) // 修改{return false;}Hash hs;// 负载因子到 1 就扩容if (_n == _tables.size()){vector<Node*> newtables(__stl_next_prime(_tables.size() + 1), nullptr);// 遍历旧表,将旧表的节点全部拿下来,挂到新表上for (size_t i = 0; i < _tables.size(); ++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;// cur头插到新表size_t hashi = hs(kot(cur->_data)) % newtables.size(); // 修改cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newtables);}size_t hashi = hs(kot(data)) % _tables.size(); // 修改Node* newnode = new Node(data);// 头插newnode->_next = _tables[hashi];_tables[hashi] = newnode; ++_n;return true;}Node* Find(const K& key){KeyOfT kot; // 修改Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key) // 修改return cur;cur = cur->_next;}return nullptr;}bool Erase(const K& key){KeyOfT kot; // 修改Hash hs;size_t hashi = hs(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;}--_n;delete cur;return true;}prev = cur;cur = cur->_next;}return false;}//...

既然哈希表新增了一个模板参数,那么我们的unordered_map和unordered_set的_ht的类型也要跟着改,我们这里用到了仿函数,它可以当参数类型传过去,我们只需要写一个返回key值的仿函数就可以解决KeyOfT问题。

// unordered_set.h
#pragma once#include "HashTable.h"namespace bs
{template<class K>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:bool insert(const K& key){return _ht.Insert(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT> _ht;};
}// unordered_map.h
#pragma once#include "HashTable.h"namespace bs
{template<class K, class V>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:bool insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;};
}

3. iterator

3.1 哈希表的迭代器的框架

模板参数加KeyOfT和Hash并且成员变量多定义了一个哈希表的指针是要在前置++中用。

template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct HTIterator
{typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> HT;typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;Node* _node;HT* _pht;HTIterator(Node* node, HT* pht):_node(node),_pht(pht){}Self& operator++(){//...}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};

3.2 解决前置++、begin()、end()

前置++的实现是一个难点,iterator中有⼀个指向结点的指针,如果当前桶下⾯还有结点,则结点的指针指向下⼀个结点即可。如果当前桶⾛完了,则需要用哈希表对象的指针计算找到下⼀个桶,⽤key值计算出当前桶位置,依次往后找下⼀个不为空的桶即可。

Self& operator++()
{if (_node->_next){// 当前桶还没有走完_node = _node->_next;}else{// 当前桶走完了,需要找下一个不为空的桶里面的第一个节点KeyOfT kot;Hash hs;size_t hashi = hs(kot(_node->_data)) % _pht->_tables.size();++hashi;while (hashi < _pht->_tables.size()){if (_pht->_tables[hashi]){_node = _pht->_tables[hashi];break;}++hashi;}}if (hashi == _pht->_tables.size()){// 所有桶都走完了,置为end()_node = nullptr;}return *this;
}

begin()返回有数据的第⼀个桶中第⼀个节点指针构造的迭代器,这⾥end()返回迭代器可以⽤空表示。

template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{typedef HashNode<T> Node;
public:typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;Iterator Begin(){if (_n == 0){return End();}for (size_t i = 0; i < _tables.size(); ++i){if (_tables[i]){return Iterator(_tables[i], this);}}// 运行逻辑上不会走到这里,但语法逻辑上要给返回值return End();}Iterator End(){return Iterator(nullptr, this);}//...

3.3 测试begin()、end()、前置++

终于写出来了,你开心极了,然后运行一下,发现报了一堆错误!

在这里插入图片描述

为什么啊!!!我感觉没一点问题啊?这里相较于用红黑树封装map和set的区别就在于迭代器和哈希表都用了对方设置了一个对方的成员变量,对于哈希表还好,迭代器在前面编译器能扫描到,但是对于迭代器就不行了,所以要在迭代器前加一个哈希表的前置声明。

// 前置声明
template<class K, class T, class KeyOfT, class Hash> // 注意声明时Hash不能带缺省值
class HashTable;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct HTIterator
{
//...

先把哈希表的迭代器、begin()和end()拿过来,然后套用一下,再测试。

// unordered_set.h
#pragma once#include "HashTable.h"namespace bs
{template<class K>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::Iterator iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}bool insert(const K& key){return _ht.Insert(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT> _ht;};void test_unordered_set(){unordered_set<int> s;s.insert(3);s.insert(4);s.insert(2);s.insert(8);s.insert(4);s.insert(11);s.insert(23);s.insert(5);s.insert(2);unordered_set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;}
}// myset.h
#pragma once#include "HashTable.h"namespace bs
{template<class K, class V>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT>::Iterator iterator;iterator begin(){return _ht.Begin();}iterator end(){return _ht.End();}bool insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;};void test_unordered_map(){unordered_map<string, string> m;m.insert({ "sort", "排序" });m.insert({ "left", "左边" });m.insert({ "right", "右边" });for (auto& e : m){cout << e.first << ":" << e.second << endl;}}
}

在这里插入图片描述
怎么又这么多报错,我要红温了!!!一看发现是迭代器用哈希表的私有成员_tables了,那怎么办,难道要把_tables改成共有吗?其实只需要让迭代器成为哈希表的友元类就行了,这样迭代器就能用哈希表的私有了。

	template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>class HashTable{// 迭代器要访问哈希表的私有成员_tables,就把迭代器变为哈希表的友元//友元声明template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node;public:typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;//...

在这里插入图片描述
欧耶!终于成功了,好有成就感啊。

4. const_iterator

const_iterator就是复制粘贴iterator的代码,再稍加修改即可。
顺便测试一下。

//HashTable.h
template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
class HashTable
{// 迭代器要访问哈希表的私有成员_tables,就把迭代器变为哈希表的友元//友元声明template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node;
public:typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator;Iterator Begin(){if (_n == 0){return End();}for (size_t i = 0; i < _tables.size(); ++i){if (_tables[i]){return Iterator(_tables[i], 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){if (_tables[i]){return ConstIterator(_tables[i], this);}}// 运行逻辑上不会走到这里,但语法逻辑上要给返回值return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}//...//unordered_set.h
#pragma once#include "HashTable.h"namespace bs
{template<class K>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::Iterator iterator;typedef typename hash_bucket::HashTable<K, K, SetKeyOfT>::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();}bool insert(const K& key){return _ht.Insert(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT> _ht;};void Print(const unordered_set<int>& s){unordered_set<int>::const_iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;}void test_unordered_set(){unordered_set<int> s;s.insert(3);s.insert(4);s.insert(2);s.insert(8);s.insert(4);s.insert(11);s.insert(23);s.insert(5);s.insert(2);unordered_set<int>::iterator it = s.begin();while (it != s.end()){cout << *it << " ";++it;}cout << endl;Print(s);}
}// unordered_map.h
#pragma once#include "HashTable.h"namespace bs
{template<class K, class V>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT>::Iterator iterator;typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT>::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();}bool insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT> _ht;};void Print(const unordered_map<string, string>& m){for (auto& e : m){cout << e.first << ":" << e.second << endl;}}void test_unordered_map(){unordered_map<string, string> m;m.insert({ "sort", "排序" });m.insert({ "left", "左边" });m.insert({ "right", "右边" });for (auto& e : m){cout << e.first << ":" << e.second << endl;}Print(m);}
}

在这里插入图片描述
怎么又报错到const迭代器了,我真的崩溃了!!!

这里报错的原因是:End()返回的是const的哈希表的指针,但是迭代器的成员变量中的哈希表的指针没加const,属于是权限放大了,因为在迭代器中我们不会改变哈希表的指针,所以直接在迭代器那里加上const就行了。

Node* _node;
const HT* _pht; // 加 constHTIterator(Node* node, const HT* pht) // 加 const:_node(node),_pht(pht)
{}

在这里插入图片描述
欧耶,我又成功了,难道我真的是C++真神吗!!!

5. key不支持修改的问题

当前,我们的unordered_map的key和value以及unordered_set的key都是可以修改的,所以要解决key不支持修改的问题。

想解决该问题只需要把unordered_map和unordered_set中,传给哈希表底层的迭代器的key值加上const以及成员变量_ht的第二个参数的类型的key值加上const即可。

//unordered_set.h
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT>::Iterator iterator;
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT>::ConstIterator const_iterator;hash_bucket::HashTable<K, const K, SetKeyOfT> _ht;//unordered_map.h
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::ConstIterator const_iterator;// pair可以修改,pair的K用const修饰,保证key不能修改,value可以修改
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. operator[]

在解决operator[]之前,要先解决insert和find的返回值类型问题;insert要返回pair<iterator, bool>,fnd要返回iterator。

// HashTable.h
pair<Iterator, bool> Insert(const T& data) // 修改
{KeyOfT kot;Iterator it = Find(kot(data)); // 修改if (it != End()) // 修改{return { it, false }; // 修改}//...return { Iterator(newnode, this), true }; // 修改
}Iterator Find(const K& key) // 修改
{KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key)return Iterator(cur, this); // 修改cur = cur->_next;}return Iterator(nullptr, this); // 修改
}// unordered_set.h
pair<iterator, bool> 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);
}//unordered_map.h
pair<iterator, bool> insert(const pair<K, V>& kv)
{return _ht.Insert(kv);
}iterator find(const K& key)
{return _ht.Find(key);
}bool erase(const K& key)
{return _ht.Erase(key);
}

unordered_map的operator[]

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

测试代码

void Print(const unordered_map<string, string>& m)
{for (auto& e : m){cout << e.first << ":" << e.second << endl;}
}void test_unordered_map()
{unordered_map<string, string> m;m.insert({ "sort", "排序" });m.insert({ "left", "左边" });m.insert({ "right", "右边" });m["insert"]; // 插入Print(m);cout << endl;m["insert"] = "插入"; // 修改Print(m);cout << endl;m["string"] = "字符串"; // 插入+修改Print(m);cout << endl;for (auto& e : m){//e.first += 'x'; // key不支持修改//e.second += 'y'; cout << e.first << ":" << e.second << endl;}Print(m);string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };unordered_map<string, int> countMap;for (auto& str : arr){// 1、不在,说明水果第一次出现,则插入{水果, 0},同时返回次数的引用,++就变成1次了// 2、在,则返回水果对应的次数的引用并++countMap[str]++;}for (auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;
}

在这里插入图片描述

7. 所有的实现代码

unordered_set.h

#pragma once#include "HashTable.h"namespace bs
{template<class K>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT>::Iterator iterator;typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT>::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<iterator, bool> 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<K, const K, SetKeyOfT> _ht;};void Print(const unordered_set<int>& s){unordered_set<int>::const_iterator it = s.begin();while (it != s.end()){//*it += 1;cout << *it << " ";++it;}cout << endl;}void test_unordered_set(){unordered_set<int> s;s.insert(3);s.insert(4);s.insert(2);s.insert(8);s.insert(4);s.insert(11);s.insert(23);s.insert(5);s.insert(2);unordered_set<int>::iterator it = s.begin();while (it != s.end()){//*it += 1; // key不支持修改cout << *it << " ";++it;}cout << endl;Print(s);}
}

unordered_map.h

#pragma once#include "HashTable.h"namespace bs
{template<class K, class V>class unordered_map{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT>::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<iterator, bool> insert(const pair<K, V>& kv){return _ht.Insert(kv);}iterator find(const K& key){return _ht.Find(key);}bool erase(const K& key){return _ht.Erase(key);}V& operator[](const K& key){pair<iterator, bool> ret = insert({ key, V() });iterator it = ret.first;return it->second;}private:hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT> _ht;};void Print(const unordered_map<string, string>& m){for (auto& e : m){cout << e.first << ":" << e.second << endl;}}void test_unordered_map(){unordered_map<string, string> m;m.insert({ "sort", "排序" });m.insert({ "left", "左边" });m.insert({ "right", "右边" });m["insert"]; // 插入Print(m);cout << endl;m["insert"] = "插入"; // 修改Print(m);cout << endl;m["string"] = "字符串"; // 插入+修改Print(m);cout << endl;for (auto& e : m){//e.first += 'x'; // key不支持修改//e.second += 'y'; cout << e.first << ":" << e.second << endl;}Print(m);string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };unordered_map<string, int> countMap;for (auto& str : arr){// 1、不在,说明水果第一次出现,则插入{水果, 0},同时返回次数的引用,++就变成1次了// 2、在,则返回水果对应的次数的引用并++countMap[str]++;}for (auto& e : countMap){cout << e.first << ":" << e.second << endl;}cout << endl;}
}

HashTable.h

#pragma once// 素数表
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;
}template<class K>
struct HashFunc
{size_t operator()(const K& key) const{return size_t(key);}
};// 特化
template<>
struct HashFunc<string>
{size_t operator()(const string& key) const{size_t hash = 0;for (auto ch : key){hash += ch;hash *= 131;}return hash;}
};namespace hash_bucket
{template<class T>struct HashNode{T _data;HashNode<T>* _next;HashNode(const T& data):_data(data),_next(nullptr){}};// 前置声明template<class K, class T, class KeyOfT, class Hash>class HashTable;template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>struct HTIterator{typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> HT;typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;Node* _node;const HT* _pht;HTIterator(Node* node, const HT* pht):_node(node),_pht(pht){}Self& operator++(){if (_node->_next){// 当前桶还没有走完_node = _node->_next;}else{// 当前桶走完了,需要找下一个不为空的桶里面的第一个节点KeyOfT kot;Hash hs;size_t hashi = hs(kot(_node->_data)) % _pht->_tables.size();++hashi;while (hashi < _pht->_tables.size()){if (_pht->_tables[hashi]){_node = _pht->_tables[hashi];break;}++hashi;}if (hashi == _pht->_tables.size()){// 所有桶都走完了,置为end()_node = nullptr;}}return *this;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>class HashTable{// 迭代器要访问哈希表的私有成员_tables,就把迭代器变为哈希表的友元//友元声明template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>friend struct HTIterator;typedef HashNode<T> Node;public:typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator;Iterator Begin(){if (_n == 0){return End();}for (size_t i = 0; i < _tables.size(); ++i){if (_tables[i]){return Iterator(_tables[i], 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){if (_tables[i]){return ConstIterator(_tables[i], this);}}// 运行逻辑上不会走到这里,但语法逻辑上要给返回值return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}HashTable(size_t n = __stl_next_prime(0)):_tables(n, nullptr),_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<Iterator, bool> Insert(const T& data){KeyOfT kot;Iterator it = Find(kot(data));if (it != End()){return { it, false };}Hash hs;// 负载因子到 1 就扩容if (_n == _tables.size()){vector<Node*> newtables(__stl_next_prime(_tables.size() + 1), nullptr);// 遍历旧表,将旧表的节点全部拿下来,挂到新表上for (size_t i = 0; i < _tables.size(); ++i){Node* cur = _tables[i];while (cur){Node* next = cur->_next;// cur头插到新表size_t hashi = hs(kot(cur->_data)) % newtables.size();cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newtables);}size_t hashi = hs(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 hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key)return Iterator(cur, this);cur = cur->_next;}return Iterator(nullptr, this);}bool Erase(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(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;}--_n;delete cur;return true;}prev = cur;cur = cur->_next;}return false;}private:vector<Node*> _tables;size_t _n; // 实际存储有效数据个数};
}

test.cpp

#include <iostream>
#include <vector>
#include <string>using namespace std;#include "HashTable.h"
#include "unordered_set.h"
#include "unordered_map.h"int main()
{bs::test_unordered_set();bs::test_unordered_map();return 0;
}
http://www.dtcms.com/a/434968.html

相关文章:

  • 有做面食的网站吗企业网络营销策划案
  • 中山做网站长沙营销企业网站建设
  • 江苏模板网站建设h5微场景制作软件
  • VSCode C/C++ 构建任务配置文件 `tasks.json` 全字段深度解析
  • 动力学系统辨识与建模
  • 做微商网站设计成都网站建设冠辰
  • 【1.SpringAI】3.SpringAI 聊天模型的介绍
  • 多模态大语言模型LISA++
  • 数据合规法律体系的宏观框架与实践要点
  • AoT - Attack on Things:A security analysis of IoT firmware updates论文梳理分析
  • 电子商务网站建设基本组成专门做推广的网站吗
  • 抄底券网站怎么做的网络平台建设怎么做
  • 给我一个免费网站吗昆明小程序开发
  • 网站建设需要哪些人员iis发布asp网站
  • 网络安全等级保护测评实施过程
  • SpringBoot + RabbitMQ 消息队列案例
  • PLC_博图系列☞基本指令”S_CU:分配参数并加计数”
  • k8s-pod调度
  • 中国工商做年报网站石家庄seo网站优化公司
  • 帝国CMS作文网题目文学文章wap+pc自适应响应式模板PHP网站源码
  • 邢台移动网站建设费用wordpress获取用户id
  • 网站设计的技能上海哪家做网站关键词排名
  • 酒店网站建设报价详情wordpress %1$s
  • 网站做支付要多少钱做产品代理上哪个网站好
  • RHEL安装
  • 列出网站开发建设的步骤通过网站建设提高企业的
  • leetcode 77 组合
  • 推广系统建站高清视频素材下载网站
  • freertos教程
  • C语言计算n个矩阵乘法