unordered_set和unordered_map模拟实现
Posted 小赵小赵福星高照~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了unordered_set和unordered_map模拟实现相关的知识,希望对你有一定的参考价值。
unordered_set和unordered_map模拟实现
文章目录
KV模型的哈希表代码
namespace bucket_hash
template<class K, class V>
struct HashNode
pair<K, V> _kv;
HashNode<K, V>* _next;
HashNode(const pair<K, V>& kv)
:_kv(kv)
, _next(nullptr)
;
size_t GetNextPrime(size_t prime)
const int PRIMECOUNT = 28;
static const size_t primeList[PRIMECOUNT] =
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
;
size_t i = 0;
for (; i < PRIMECOUNT; ++i)
if (primeList[i] > prime)
return primeList[i];
return primeList[i];
template<class K, class V, class Hash = HashFunc<K>>
class HashTable
typedef HashNode<K, V> Node;
public:
// 拷贝 和 赋值 需要自己实现桶的拷贝
~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;
_n = 0;
bool Erase(const K& key)
if (_tables.size() == 0)
return false;
Hash hf;
// 素数
size_t index = hf(key) % _tables.size();
Node* prev = nullptr;
Node* cur = _tables[index];
while (cur)
if (cur->_kv.first == key)
// 1、cur是头结点
// 2、非头节点
if (prev == nullptr)
_tables[index] = cur->_next;
else
prev->_next = cur->_next;
delete cur;
--_n;
return true;
else
prev = cur;
cur = cur->_next;
return false;
Node* Find(const K& key)
if (_tables.size() == 0)
return nullptr;
Hash hf;
size_t index = hf(key) % _tables.size();
Node* cur = _tables[index];
while (cur)
if (cur->_kv.first == key)
return cur;
else
cur = cur->_next;
return nullptr;
bool Insert(const pair<K, V>& kv)
Hash hf;
//当负载因子到1时,进行扩容
if (_n == _tables.size())
//size_t newSize = _tables.size() == 0 ? 10 : _tables.size() * 2;
size_t newSize = GetNextPrime(_tables.size());
//HashTable<K, V> newHT;
vector<Node*> newtables;
newtables.resize(newSize, nullptr);
for (size_t i = 0; i < _tables.size(); ++i)
Node* cur = _tables[i];
while (cur)
Node* next = cur->_next;
size_t index = hf(cur->_kv.first) % newSize;
cur->_next = newtables[index];
newtables[index] = cur;
cur = next;
_tables[i] = nullptr;
newtables.swap(_tables);
size_t index = hf(kv.first) % _tables.size();
Node* cur = _tables[index];
while (cur)
if (cur->_kv.first == kv.first)
return false;
else
cur = cur->_next;
Node* newnode = new Node(kv);
newnode->_next = _tables[index];
_tables[index] = newnode;
++_n;
return true;
private:
vector<Node*> _tables;
size_t _n = 0; // 存储多少有效数据
;
我们以KV模型的哈希表进行改造实现unordered_set和unordered_map:
哈希表的改造
模板参数的改造
template<class K, class T, class KeyOfT, class Hash = HashFunc<T> >
class HashBucket;
K:关键码类型
T: 不同容器T的类型不同,如果是unordered_map,T代表一个键值对,如果是unordered_set,T为 K
KeyOfT: 在哈希表中需要取到value,因为T的类型不同,通过value取key的方式就不同,详细见unordered_map/set的实现
Hash: 哈希函数仿函数对象类型,哈希函数使用除留余数法,如果是Key为string类型,需要将Key转换为整形数字才能取模
哈希表节点结构
template<class T>
struct HashNode
T _data;
HashNode<T>* _next;
HashNode(const T& data)
:_data(data)
, _next(nullptr)
;
如果是unordered_map,T代表一个键值对,如果是unordered_set,T为 K
哈希表迭代器模拟实现
哈希表的迭代器我们应该怎么实现呢?
哈希表的迭代器也是对节点指针进行了封装,我们想一想++操作怎么实现呢?一个桶遍历完了如何跳转到下一个桶?为了实现桶的跳转,我们在迭代器中还需要一个哈希表的指针
operator++模拟实现
当下一个节点不为空时,++后的节点就在当前桶,返回即可,当下一个节点为空时,我们需要找下一个桶,首先通过当前节点计算找到当前节点所在桶的位置index,计算出后,++index即找到了下一个桶,当下一个桶存在时,如果下一个桶里面有数据(即不为空),则将第一个数据给当前节点,就实现了++,否则继续找下一个桶,当循环出来时,有可能是找到++后的节点了,也有可能说明走完了后面没有桶了,所以循环出来需要判断是不是没有桶了,没有桶则返回nullptr
Self operator++()
if (_node->_next) // 在当前桶迭代
_node = _node->_next;
else // 找下一个桶
KeyOfT kot;
const K& key = kot(_node->_data);
Hash hf;
size_t index = hf(key) % _ht->_tables.size();
++index;
_node = nullptr;
while (index < _ht->_tables.size())
if (_ht->_tables[index])
_node = _ht->_tables[index];
break;
else
++index;
// 后面没有桶了
if (index == _ht->_tables.size())
_node = nullptr;
return *this;
operator*的模拟实现
返回节点的数据的引用即可
T& operator*()
return _node->_data;
operator->的模拟实现
返回节点数据的地址即可
T* operator->()
return &_node->_data;
operator==和operator!=的模拟实现
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>
class HashTable;
template<class K, class T, class Hash, class KeyOfT>
struct HTIterator
typedef HashNode<T> Node;
typedef HashTable<K, T, Hash, KeyOfT> HT;
typedef HTIterator<K, T, Hash, KeyOfT> Self;
Node* _node;
HT* _ht;
HTIterator(Node* node, HT* ht)
:_node(node)
, _ht(ht)
bool operator!=(const Self& s) const
return _node != s._node;
bool operator==(const Self& s) const
return _node == s._node;
T& operator*()
return _node->_data;
T* operator->()
return &_node->_data;
Self operator++()
if (_node->_next) // 在当前桶迭代
_node = _node->_next;
else // 找下一个桶
KeyOfT kot;
const K& key = kot(_node->_data);
Hash hf;
size_t index = hf(key) % _ht->_tables.size();
++index;
_node = nullptr;
while (index < _ht->_tables.size())
if (_ht->_tables[index])
_node = _ht->_tables[index];
break;
else
++index;
// 后面没有桶了
if (index == _ht->_tables.size())
_node = nullptr;
return *this;
;
然后在哈希表中实现迭代器的相关函数:
template<class K, class T, class KeyOfT, class Hash = HashFunc<K>>
class HashTable
typedef HashNode<T> Node;
friend struct HTIterator<K, T, Hash, KeyOfT>;//将迭代器设置成友元,让迭代器访问哈希表的私有
public:
typedef HTIterator<K, T, Hash, KeyOfT> iterator;
iterator begin()
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);
private:
vector<Node*> _table;
size_t _n = 0;
;
哈希表的最终代码
namespace bucket_hash
template<class T>
struct HashNode
T _data;
HashNode<T>* _next;
HashNode(const T& data)
:_data(data)
, _next(nullptr)
;
size_t GetNextPrime(size_t prime)
const int PRIMECOUNT = 28;
static const size_t primeList[PRIMECOUNT] =
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
;
size_t i = 0;
for (; i < PRIMECOUNT; ++i)
if (primeList[i] > prime)
return primeList[i];
return primeList[i];
// 前置声明
template<class K, class T, class Hash, class KeyOfT>
class HashTable;
template<class K, class T, class Hash, class KeyOfT>
struct HTIterator
typedef HashNode<T> Node;
typedef HashTable<K, T, Hash, KeyOfT> HT;
typedef HTIterator<K, T, Hash, KeyOfT> Self;
Node* _node;
HT* _ht;
HTIterator(Node* node, HT* ht)
:_node(node)
, _ht(ht)
bool operator!=(const Self& s) const
return _node != s._node;
T& operator*()
return _node->_data;
T* operator->()
return &_node->_data;
Self operator++()
if (_node->_next) // 在当前桶迭代
_node = _node->_next;
else // 找下一个桶
KeyOfT kot;
const K& key = kot(_node->_data);
Hash hf;
size_t index = hf(key) % _ht->_tables.size();
++index;
_node = nullptr;
while (index < _ht->_tables.size())
if (_ht->_tables[index])
_node = _htunordered_set和unordered_map模拟实现
unordered_set和unordered_map模拟实现
C++之unordered_map和unordered_set以及哈希详解
unordered_map和unordered_set的模拟实现