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

cpp
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类访问这个类的私有限定的内容
cpp
template<class K,class T,class Ref,class Ptr,class Keyft,class Hash>
friend struct HTIterator;
2.Begin()
如果没有插入一个则直接返回End(),有则需要循环去遍历找到第一个的位置,找到就返回迭代器,这里的this是类的对象,也就是指向HashTable的指针。
cpp
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.析构函数
因为哈希桶可能一个位置挂了多个结点在下面,所以要循环去把当前位置的结点删除,再去遍历哈希表找到下一个存在桶的位置。
cpp
~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++,返回时用了隐式类型转换。

cpp
pair<Iterator, bool> Insert(const T& data)
{
KeyOft kot;
Iterator it = Find(kot(data));
if (it != End())
return { it,false };
Hash hash;
if (_n == _tables.size())
{
vector<Node*> 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().
cpp
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--。
cpp
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
cpp
#pragma once
#include<vector>
template<class K>
struct HashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
template<>
struct HashFunc<string>
{
size_t operator()(const string& s)
{
// BKDR
size_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
{
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* _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;
}
};
template<class K,class T,class KeyOft,class Hash>
class HashTable
{
//友元声明
template<class K,class T,class Ref,class Ptr,class Keyft,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++)
{
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<Iterator, bool> Insert(const T& data)
{
KeyOft kot;
Iterator it = Find(kot(data));
if (it != End())
return { it,false };
Hash hash;
if (_n == _tables.size())
{
vector<Node*> 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<Node*> _tables;
size_t _n = 0;
};
}
Unordered_set
cpp
#pragma once
#include"HashTable.h"
namespace bit
{
template<class K, class Hash = HashFunc<K>>
class unordered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::Iterator iterator;
typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, 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();
}
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, Hash> _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;
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<int> s;
for (auto e : a)
{
s.insert(e);
}
unordered_set<int>::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
cpp
#pragma once
#include"HashTable.h"
namespace bit
{
template<class K, class V, class Hash = HashFunc<K>>
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, Hash>::Iterator iterator;
typedef typename hash_bucket::HashTable<K, pair<const K, V>,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<iterator, bool> ret = insert({ key,V() });
return ret.first->second;
}
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);
}
private:
hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
};
void test_map1()
{
unordered_map<string, string> 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<string, string>::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
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<set>
#include<unordered_set>
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<int, int> 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<string, string> ht1;
// for (auto& e : a1)
// {
// ht1.Insert({ e, e });
// }
//
// cout << HashFunc<string>()("abcd") << endl;
// cout << HashFunc<string>()("bcad") << endl;
// cout << HashFunc<string>()("aadd") << endl;
//
// int a2[] = { -19,-30,5,36,13,20,21,12 };
// HashTable<int, int> ht2;
// for (auto e : a2)
// {
// ht2.Insert({ e, e });
// }
//
// // 哈希冲突
// HashTable<Date, int, DateHashFunc> 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;
}