哈希表封装myunordered_map以及set - 详解
1.unordered_set
1.仿函数
这个是为了把对象的键值取出来
struct SetKeyOfT
{const K& operator()(const K& key){return key;}
};
2.提供接口
把封装好的函数在调用,调用的函数为接口
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 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);
}
3.成员变量
再主函数里得到模板的参数,确定了每个变量的具体类型
hash_bucket::HashTable _ht;
2.unordered_Map
1.仿函数
对于键值对,要单独取出键值来
struct MapKeyOfT
{const K& operator()(const pair& kv){return kv.first;}
};
2.接口函数
下标访问先用插入函数去找到位置,因为插入函数插入失败与成功都会返回当前位置的pair,pair的first是迭代器,而迭代器又是结点的指针,所以用->重载函数可以得到指定的结点,而结点也是pair,second就是值。
iterator begin()
{return _ht.Begin();
}
iterator end()
{return _ht.End();
}
const_iterator begin() const
{return _ht.Begin();
}
const_iterator end() const
{return _ht.End();
}
V& operator[](const K& key)
{pair ret = insert({ key,V() });return ret.first->second;
}
pair insert(const pair& kv)
{return _ht.Insert(kv);
}
iterator Find(const K& key)
{return _ht.Find(key);
}
bool Erase(const K& key)
{return _ht.Erase(key);
}
3.成员变量
hash_bucket::HashTable, MapKeyOfT, Hash> _ht;
4.前置声明
因为只有类内部才可以不用向上查找,所以要前置声明是编译器知道有这个类存在。
//前置声明
template
class HashTable;
3.HashTable
1.结点定义
这里T是数据的类型,T会在哈希表的类里面知道
template
struct HashNode
{T _data;HashNode* _next;HashNode(const T& data):_data(data),_next(nullptr){}
};
2.迭代器操作
1.成员函数
结点的指针和哈希表的指针
typedef HashNode Node;
typedef HashTable HT;
typedef HTIterator Self;
Node* _node;
const HT* _ht;
HTIterator(Node* node,const HT* ht):_node(node),_ht(ht)
{}
2.++的实现
判断结点的下一个是否为空,为空就直接往下走一格,不为空就要到下一个地方去,比如2走完了就要去8的位置,先计算出此位置的哈希值,然后通过循环遍历,只要把哈希值+1就会到下一个地方,就一直加,直到找到不为空的地方,还需要判断最后的哈希值是否跟哈希表的大小一样,一样就说明上面的循环不是break出来的而是条件不符合出来的,则把指针_node指向nullptr,最后返回*this,也就是这个类的对象此位置的迭代器。

Self& operator++()
{if (_node->_next){_node = _node->_next;}else{KeyOft kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();++hashi;while (hashi < _ht->_tables.size()){_node = _ht->_tables[hashi];if (_node)break;++hashi;}if (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;
}
4.HashTable
1.友元声明
可以让HTIterator类访问这个类的私有限定的内容
template
friend struct HTIterator;
2.Begin()
如果没有插入一个则直接返回End(),有则需要循环去遍历找到第一个的位置,找到就返回迭代器,这里的this是类的对象,也就是指向HashTable的指针。
Iterator Begin()
{if (_n == 0)return End();for (size_t i = 0; i <_tables.size(); i++){Node* cur = _tables[i];if (cur)return Iterator(cur, this);}return End();
}
Iterator End()
{return Iterator(nullptr, this);
}
3.析构函数
因为哈希桶可能一个位置挂了多个结点在下面,所以要循环去把当前位置的结点删除,再去遍历哈希表找到下一个存在桶的位置。
~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;}}
4.Insert函数
插入前需要判断是否存在当前的哈希表里,用Find函数去查找,返回的迭代器不等于End就说明存在,不能插入,如果负载因子等于1需要扩容,通过素数表得到空间大小,接着是把旧表内容移到新表,kot得到键值,hash得到哈希值,双重仿函数,cur->next是把旧表结点指向新表的位置,然后结点指针取代新表的指针,每一个新来的都会头插,插入成功还要把_n++,返回时用了隐式类型转换。

pair Insert(const T& data)
{KeyOft kot;Iterator it = Find(kot(data));if (it != End())return { it,false };Hash hash;if (_n == _tables.size()){vector newTable(__stl_next_prime(_tables.size() + 1));for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;size_t hashi = hash(kot(cur->_data)) % newTable.size();cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTable);}size_t hashi = hash(kot(data)) % _tables.size();Node* newnode = new Node(data);newnode->_next = _tables[hashi];_tables[hashi] = newnode;++_n;return { Iterator(newnode,this),true };
}
5.Find函数
通过给的键值计算出哈希值找到对应的挂载结点的位置,接着去遍历结点找到指定结点,遍历结束则没有找到就返回End().
Iterator Find(const K& key)
{KeyOft kot;Hash hash;size_t hashi = hash(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key)return Iterator(cur, this);cur = cur->_next;}return End();
}
6.Erase函数
这里需要设置一个prev变量,如果删除的结点是在中间的话就需要把前一个和后一个接在一起,先得到哈希值找到挂载结点的位置,然后循环遍历找指定结点,如果prev变量还是nullptr就说明是第一个结点删除,删除后要把_n--。
bool Erase(const K& key)
{KeyOft kot;size_t hashi = 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;}delete cur;--_n;return true;}else{prev = cur;cur = cur->_next;}}return false;
}
5.总代码
HashTable
#pragma once
#include
template
struct HashFunc
{size_t operator()(const K& key){return (size_t)key;}
};
template<>
struct HashFunc
{size_t operator()(const string& s){// BKDRsize_t hash = 0;for (auto ch : s){hash += ch;hash *= 131;}return hash;}
};
//
//
//
//
//
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;
}
namespace hash_bucket
{templatestruct HashNode{T _data;HashNode* _next;HashNode(const T& data):_data(data),_next(nullptr){}};//前置声明templateclass HashTable;templatestruct HTIterator{typedef HashNode Node;typedef HashTable HT;typedef HTIterator Self;Node* _node;const HT* _ht;HTIterator(Node* node,const HT* ht):_node(node),_ht(ht){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s){return _node != s._node;}Self& operator++(){if (_node->_next){_node = _node->_next;}else{KeyOft kot;Hash hash;size_t hashi = hash(kot(_node->_data)) % _ht->_tables.size();++hashi;while (hashi < _ht->_tables.size()){_node = _ht->_tables[hashi];if (_node)break;++hashi;}if (hashi == _ht->_tables.size()){_node = nullptr;}}return *this;}};templateclass HashTable{//友元声明templatefriend struct HTIterator;typedef HashNode Node;public:typedef HTIterator Iterator; //你的这里是大写的typedef HTIterator ConstIterator;Iterator Begin(){if (_n == 0)return End();for (size_t i = 0; i <_tables.size(); i++){Node* cur = _tables[i];if (cur)return Iterator(cur, 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++){Node* cur = _tables[i];if (cur){return ConstIterator(cur, this);}}return End();}ConstIterator End() const{return ConstIterator(nullptr, this);}HashTable():_tables(__stl_next_prime(0)), _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 Insert(const T& data){KeyOft kot;Iterator it = Find(kot(data));if (it != End())return { it,false };Hash hash;if (_n == _tables.size()){vector newTable(__stl_next_prime(_tables.size() + 1));for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;size_t hashi = hash(kot(cur->_data)) % newTable.size();cur->_next = newTable[hashi];newTable[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newTable);}size_t hashi = hash(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 hash;size_t hashi = hash(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key)return Iterator(cur, this);cur = cur->_next;}return End();}bool Erase(const K& key){KeyOft kot;size_t hashi = 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;}delete cur;--_n;return true;}else{prev = cur;cur = cur->_next;}}return false;}private:vector _tables;size_t _n = 0;};
}
Unordered_set
#pragma once
#include"HashTable.h"
namespace bit
{template>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename hash_bucket::HashTable::Iterator iterator;typedef typename hash_bucket::HashTable::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 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 _ht;};void print(const unordered_set& s){unordered_set::const_iterator it = s.begin();while (it != s.end()){//*it = 1;cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;}void test_set1(){int a[] = { 3,11,86,7,88,82,1,881,5,6,7,6 };unordered_set s;for (auto e : a){s.insert(e);}unordered_set::iterator it = s.begin();while (it != s.end()){//*it = 1;cout << *it << " ";++it;}cout << endl;for (auto e : s){cout << e << " ";}cout << endl;print(s);}
}
Unordered_map
#pragma once
#include"HashTable.h"
namespace bit
{template>class unordered_map{struct MapKeyOfT{const K& operator()(const pair& kv){return kv.first;}};public:typedef typename hash_bucket::HashTable,MapKeyOfT, Hash>::Iterator iterator;typedef typename hash_bucket::HashTable,MapKeyOfT, Hash>::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();}V& operator[](const K& key){pair ret = insert({ key,V() });return ret.first->second;}pair insert(const pair& kv){return _ht.Insert(kv);}iterator Find(const K& key){return _ht.Find(key);}bool Erase(const K& key){return _ht.Erase(key);}private:hash_bucket::HashTable, MapKeyOfT, Hash> _ht;};void test_map1(){unordered_map dict;dict.insert({ "sort", "排序" });dict.insert({ "字符串", "string" });dict.insert({ "sort", "排序" });dict.insert({ "left", "左边" });dict.insert({ "right", "右边" });dict["left"] = "左边,剩余";dict["insert"] = "插入";dict["string"];for (auto& kv : dict){cout << kv.first << ":" << kv.second << endl;}cout << endl;unordered_map::iterator it = dict.begin();while (it != dict.end()){// 不能修改first,可以修改second//it->first += 'x';it->second += 'x';cout << it->first << ":" << it->second << endl;++it;}cout << endl;}
}
test
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
using namespace std;
#include"HashTable.h"
//int main()
//{
// //int a[] = { 19,30,52,63,11,22 };
// int a[] = { 19,30,5,36,13,20,21,12 };
// HashTable ht;
// for (auto e : a)
// {
// ht.Insert({ e, e });
// }
//
// //ht.Insert({ 15, 15 });
//
// ht.Erase(30);
// if (ht.Find(20))
// {
// cout << "找到了" << endl;
// }
//
// if (ht.Find(30))
// {
// cout << "找到了" << endl;
// }
// else
// {
// cout << "没有找到" << endl;
// }
//
// return 0;
//}
//struct StringHashFunc
//{
// size_t operator()(const string& s)
// {
// size_t hash = 0;
// for (auto ch : s)
// {
// hash += ch;
// }
//
// return hash;
// }
//};
struct Date
{int _year;int _month;int _day;Date(int year = 1, int month = 1, int day = 1):_year(year), _month(month), _day(day){}bool operator==(const Date& d){return _year == d._year&& _month == d._month&& _day == d._day;}
};
struct DateHashFunc
{size_t operator()(const Date& d){size_t hash = 0;hash += d._year;hash *= 131;hash += d._month;hash *= 131;hash += d._day;hash *= 131;return hash;}
};
//int main()
//{
// //int a[] = { 19,30,52,63,11,22 };
//
// const char* a1[] = { "abcd", "sort", "insert" };
// HashTable ht1;
// for (auto& e : a1)
// {
// ht1.Insert({ e, e });
// }
//
// cout << HashFunc()("abcd") << endl;
// cout << HashFunc()("bcad") << endl;
// cout << HashFunc()("aadd") << endl;
//
// int a2[] = { -19,-30,5,36,13,20,21,12 };
// HashTable ht2;
// for (auto e : a2)
// {
// ht2.Insert({ e, e });
// }
//
// // 哈希冲突
// HashTable ht;
// ht.Insert({ { 2024, 10, 12 }, 1});
// ht.Insert({ { 2024, 12, 10 }, 1 });
//
// return 0;
//}
#include"Unordered_map.h"
#include"Unordered_set.h"
int main()
{//bit::test_set1();bit::test_map1();return 0;
}