unordered_map和unordered_set的封装
- 1. hash模版的改变
- 1.1 hash类模板 头的改变
- 1.2 封装迭代器类
- 1.2.1 构造 && 拷贝构造
- 1.2.2. ++
- 1.2.3. 其他运算符重载
- 1.3 hash类实现普通迭代器和const迭代器
- 2. unordered_set的底层逻辑
- 3. unordered_map的底层逻辑
- 4. 源码
- 4.1 hash类
- 4.2 unordered_set类
- 4.3 unordered_map类
1. hash模版的改变
1.1 hash类模板 头的改变
1.2 封装迭代器类
🗨️ 为什么要传那么多的参数? 为什么要有hash类的前置声明呢? 为什么要多一个哈希表指针成员变量呢?
- 加加操作中, 虽然可以找到
桶号
, 但是没有哈希桶
是没有意义的 && 哈希表指针也是可以完成哈希桶的操作的 ⇒ 所以在迭代器类中需要有一个哈希表指针
由于要有哈希表指针 , 所以会用到hash类的相关参数(T - 数据类型, KeyofT, Com - 比较逻辑) 和 相关函数(比如构造啥的)
⇒迭代器类要有足够多的参数 和 hash前置声明一下
1.2.1 构造 && 拷贝构造
- 构造
_iterator(Node* node,const hash<K, T, KeyofT, Com>* pht)
:_node(node)
, _pht(pht)
{}
- 用普通迭代器初始化const迭代器
_iterator(const Iterator& node)
:_node(node._node)
, _pht(node._pht)
{}
1.2.2. ++
有两种情况 :
- 当前桶还有数据 — — 返回当前桶当前位置的下一个元素即可
- 当前桶没有数据 — — 去找下一个有元素的桶
self& operator++()
{
Com com;
KeyofT kot;
size_t hashi = com(kot(_node->_data)) % _pht->_table.size();
// 当前桶还有节点
if (_node->_next)
{
_node = _node->_next;
}
// 当前桶没有节点
else
{
hashi++;
while (hashi < _pht->_table.size())
{
// 找到了, 就返回
if (_pht->_table[hashi])
{
_node = _pht->_table[hashi];
return *this;
}
else
{
hashi++;
}
}
// 说明后面的桶都没有元素了, 那就返回nullptr
_node = nullptr;
}
return *this;
}
1.2.3. 其他运算符重载
- operator==
bool operator==(const self& it)
{
return _node == it._node;
}
- operator!=
bool operator!=(const self& it)
{
return _node != it._node;
}
- operator*
Ptr operator*()
{
return _node->_data;
}
- operator->
Ref operator->()
{
return &(_node->_data);
}
1.3 hash类实现普通迭代器和const迭代器
- 类型
typedef _iterator<K,T, T&, T*, KeyofT, Com> iterator;
typedef _iterator<K,T, const T&, const T*,KeyofT, Com> const_iterator;
- begin end
begin — — 返回第一个有元素的桶的地址
end — — 返回空指针
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
return iterator(_table[i], this);
}
}
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator begin()const
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
return const_iterator(_table[i], this);
}
}
}
const_iterator end()const
{
return const_iterator(nullptr, this);
}
2. unordered_set的底层逻辑
- SetofT — — 提取数据中的的key
struct SetofT
{
K operator()(const K& key)
{
return key;
}
};
- 迭代器类型
typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator iterator;
typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator const_iterator;
- begin, end
iterator begin()const
{
return _ht.begin();
}
iterator end()const
{
return _ht.end();
}
- erase
bool erase(const K& key)
{
return _ht.erase(key);
}
- find
iterator find(const K& key)
{
typename hash_bucket::hash<K, K, SetofT>::iterator ret = _ht.find(key);
iterator res = ret;
return res;
}
- insert
pair<iterator, bool>& insert(const K& key)
{
pair<hash_bucket::hash<K, K, SetofT>::iterator, bool> ret = _ht.insert(key);
pair<iterator, bool> res = ret;
return res;
}
3. unordered_map的底层逻辑
- MapofT
struct MapofT
{
K operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
- 迭代器类型
typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::iterator iterator;
typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::const_iterator const_iterator;
- begin, end
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
const_iterator begin()const
{
return _ht.begin();
}
const_iterator end()const
{
return _ht.end();
}
- erase
bool erase(const K& key)
{
return _ht.erase(key);
}
- find
iterator find(const K& key)
{
return _ht.find(key);
}
- insert
pair<iterator, bool> insert(const pair<const K, V>& kv)
{
return _ht.insert(kv);
}
- operator[ ]
V& operator[](const K& key)
{
pair<iterator, bool> res = _ht.insert(make_pair(key, V()));
return res.first->second;
}
4. 源码
4.1 hash类
#pragma once
#include<iostream>
#include<vector>
using namespace std;
namespace hash_bucket
{
template<class T>
struct HashData
{
public:
HashData(const T& kv)
:_data(kv)
{}
public:
T _data;
HashData<T>* _next;
};
template<class K>
struct DEFAULT
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
template<>
struct DEFAULT<string>
{
size_t operator()(const string& key)
{
int res = 0;
for (auto e : key)
{
res += e * 131;
}
return res;
}
};
// 前置声明
template<class K, class T, class KeyofT, class Com>
struct hash;
template<class K, class T, class Ptr, class Ref, class KeyofT, class Com>
struct _iterator
{
typedef HashData<T> Node;
typedef _iterator<K, T,Ptr, Ref, KeyofT, Com> self;
typedef _iterator<K, T,T&, T*, KeyofT, Com> Iterator;
Node* _node;
const hash<K, T, KeyofT, Com>* _pht;
_iterator(Node* node,const hash<K, T, KeyofT, Com>* pht)
:_node(node)
, _pht(pht)
{}
_iterator(const Iterator& node)
:_node(node._node)
, _pht(node._pht)
{}
self& operator++()
{
Com com;
KeyofT kot;
size_t hashi = com(kot(_node->_data)) % _pht->_table.size();
if (_node->_next)
{
_node = _node->_next;
}
else
{
hashi++;
while (hashi < _pht->_table.size())
{
if (_pht->_table[hashi])
{
_node = _pht->_table[hashi];
return *this;
}
else
{
hashi++;
}
}
_node = nullptr;
}
return *this;
}
bool operator!=(const self& it)
{
return _node != it._node;
}
Ptr operator*()
{
return _node->_data;
}
Ref operator->()
{
return &(_node->_data);
}
};
template<class K, class T, class KeyofT, class Com = DEFAULT<K>>
struct hash
{
typedef HashData<T> Node;
// 友元
//template<class K, class Ptr, class Ref, class T, class KeyofT, class Com>
//friend struct _iterator;
public:
typedef _iterator<K,T, T&, T*, KeyofT, Com> iterator;
typedef _iterator<K,T, const T&, const T*,KeyofT, Com> const_iterator;
public:
iterator begin()
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
return iterator(_table[i], this);
}
}
}
iterator end()
{
return iterator(nullptr, this);
}
const_iterator begin()const
{
for (size_t i = 0; i < _table.size(); i++)
{
if (_table[i])
{
return const_iterator(_table[i], this);
}
}
}
const_iterator end()const
{
return const_iterator(nullptr, this);
}
hash()
{
_table.resize(4, nullptr);
}
iterator find(const K& key)
{
size_t hashi = com(key) % _table.size();
Node* cur = _table[hashi];
while (cur)
{
if (com(kot(cur->_data)) == com(key))
{
return iterator(cur, this);
}
cur = cur->_next;
}
return iterator(nullptr, this);
}
pair<iterator, bool> insert(const T& kv)
{
iterator res = find(kot(kv));
if (res != end())
{
// 不要返回空, 要返回重复值的指针, 以便与后面的 [] 来进行修改value
return make_pair(res, false);
}
// 扩容逻辑
if (_sz == _table.size())
{
vector<Node*> new_table;
new_table.resize(_table.size() * 2, nullptr);
for (size_t i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
while (cur)
{
Node* next = cur->_next;
size_t hashi = com(kot(cur->_data)) % new_table.size();
cur->_next = new_table[hashi];
new_table[hashi] = cur;
cur = next;
}
}
_table.swap(new_table);
}
// 插入逻辑
size_t hashi = com(kot(kv)) % _table.size();
Node* newnode = new Node(kv);
newnode->_next = _table[hashi];
_table[hashi] = newnode;
++_sz;
return make_pair(iterator(_table[hashi], this), true);
}
bool erase(const K& key)
{
Node* res = find(key);
if (res == nullptr)
{
return false;
}
else
{
size_t hashi = com(key) % _table.size();
Node* cur = _table[hashi];
Node* prev = nullptr;
while (cur)
{
if (cur->_data.first == key)
{
if (prev == nullptr)
{
_table[hashi] = cur->_next;
}
else
{
prev->_next = cur->_next;
}
}
prev = cur;
cur = cur->_next;
}
--_sz;
delete cur;
}
return true;
}
void print()
{
for (int i = 0; i < _table.size(); i++)
{
Node* cur = _table[i];
printf("[%d]->", i);
while (cur)
{
printf("%d", cur->_data.first);
cur = cur->_next;
}
cout << "NULL" << endl;
}
cout << endl;
}
public:
vector<Node*> _table;
size_t _sz = 0;
Com com;
KeyofT kot;
};
}
4.2 unordered_set类
#pragma once
#include"hash_bucket.h"
#include<iostream>
using namespace std;
namespace muyu
{
template<class K>
class unordered_set
{
struct SetofT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator iterator;
typedef typename hash_bucket::hash<K, K, SetofT>::const_iterator const_iterator;
iterator begin()const
{
return _ht.begin();
}
iterator end()const
{
return _ht.end();
}
pair<iterator, bool>& insert(const K& key)
{
pair<hash_bucket::hash<K, K, SetofT>::iterator, bool> ret = _ht.insert(key);
pair<iterator, bool> res = ret;
return res;
}
bool erase(const K& key)
{
return _ht.erase(key);
}
iterator find(const K& key)
{
typename hash_bucket::hash<K, K, SetofT>::iterator ret = _ht.find(key);
iterator res = ret;
return res;
}
private:
hash_bucket::hash<K, K, SetofT> _ht;
};
}
4.3 unordered_map类
#pragma once
#include"hash_bucket.h"
#include<iostream>
using namespace std;
namespace muyu
{
template<class K, class V>
class unordered_map
{
struct MapofT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::iterator iterator;
typedef typename hash_bucket::hash<K, pair<const K, V>, MapofT>::const_iterator 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<const K, V>& kv)
{
return _ht.insert(kv);
}
V& operator[](const K& key)
{
pair<iterator, bool> res = _ht.insert(make_pair(key, V()));
return res.first->second;
}
bool erase(const K& key)
{
return _ht.erase(key);
}
iterator find(const K& key)
{
return _ht.find(key);
}
private:
hash_bucket::hash<K, pair<const K, V>, MapofT> _ht;
};
}
爱此倚栏干,谁同寓目闲。
轻阴弄晴日,秀色隐空山。
岛树萧疏外,征帆杳霭间。
予虽江上老,心羡白云还。
— — 岳飞 <题池州翠光寺>