目录
[1. 复用哈希表](#1. 复用哈希表)
[2. Iterator和ConstIterator的实现](#2. Iterator和ConstIterator的实现)
[3. 实现unordered_set](#3. 实现unordered_set)
[4. 实现unordered_map](#4. 实现unordered_map)
[5. 完整代码](#5. 完整代码)
本篇文章我们要实现unodered_map和unodered_set,基本的大致思路其实和前面map和set的封装差不多:【C++】map和set的封装-CSDN博客
所以相同的内容我就不再赘述了,本篇主要就是展示一下大致思路,代码部分偏多,大家可以一起试试实现一下哦!
1. 复用哈希表
我们在前面的文章中就已经实现过哈希表了:【C++】哈希表的实现-CSDN博客
本篇文章中实现unordered_map和unordered_set复用的是用链地址法实现的哈希表(即哈希桶)
在此基础上稍作改动:
cpp
//解决有些key不能取模的问题
template<class K>
struct HashKey
{
//能转化成size_t的,就直接转换
size_t operator()(const K& k)
{
return size_t(k);
}
};
//特化
template<>
struct HashKey<string>
{
size_t operator()(const string& s)
{
size_t ret = 0;
for (auto e : s)
{
ret *= 31;
ret += e;
}
return ret;
}
};
//链地址法
namespace hash_bucket
{
template<class T>
struct HashNode
{
T _data;
HashNode* _next;
HashNode(const T& data)
:_data(data)
, _next(nullptr)
{}
};
template<class K,class T,class KeyOfT,class Hash = HashKey<K>>
class HashTable {
public:
typedef HashNode<T> Node;
HashTable()
{
_tables.resize(__stl_next_prime(0),nullptr);
}
~HashTable()
{
for (int i = 0; i < _tables.size(); i++)
{
while (_tables[i])
{
Node* del = _tables[i];
_tables[i] = _tables[i]->_next;
delete del;
del = nullptr;
}
}
_size = 0;
}
bool Insert(const T& data)
{
KeyOfT kot;
Hash h;
if (Find(kot(data)))
return false;
//负载因子大于0.7------扩容
if ((double)_size / (double)_tables.size() > 0.7)
{
vector<Node*> newHT;
newHT.resize(__stl_next_prime((unsigned long)_tables.size() + 1), nullptr);
for (int i = 0; i < _tables.size(); i++)
{
while(_tables[i])
{
size_t hash0 = h(kot(_tables[i]->_data)) % newHT.size();
Node* newnode = _tables[i];
_tables[i] = newnode->_next;
newnode->_next = newHT[hash0];
newHT[hash0] = newnode;
}
}
newHT.swap(_tables);
}
Node* newnode = new Node(data);
size_t hash0 = h(kot(data)) % _tables.size();
//头插
newnode->_next = _tables[hash0];
_tables[hash0] = newnode;
_size++;
return true;
}
Node* Find(const K& key)
{
Hash h;
KeyOfT kot;
size_t hash0 = h(key) % _tables.size();
for (int i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
if (kot(cur->_data) == key)
{
return cur;
}
cur = cur->_next;
}
}
return nullptr;
}
bool Erase(const K& key)
{
Hash h;
KeyOfT kot;
size_t hash0 = h(key) % _tables.size();
for (int i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
Node* prev = nullptr;
while (cur)
{
if (kot(cur->_data) == key)
{
if (prev == nullptr)
_tables[i] = cur->_next;
else
{
prev->_next = cur->_next;
}
delete cur;
cur = nullptr;
_size--;
return true;
}
prev = cur;
cur = cur->_next;
}
}
return false;
}
private:
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;
}
vector<Node*> _tables;
size_t _size = 0;
};
}
2. Iterator和ConstIterator的实现
cpp
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;
}
bool operator!=(const Self& s)
{
return _node != s._node;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
KeyOfT kot;
Hash h;
size_t hashi = h(kot(_node->_data)) % _ht->_tables.size();
hashi++;
while (hashi<_ht->_tables.size())
{
if (_ht->_tables[hashi])
{
_node = _ht->_tables[hashi];
break;
}
else
{
hashi++;
}
}
if (hashi == _ht->_tables.size())
_node = nullptr;
}
return *this;
}
};
template<class K,class T,class KeyOfT,class Hash = HashKey<K>>
class HashTable {
// 友元声明
template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
friend struct HTIterator;
public:
typedef HashNode<T> Node;
typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;
typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator;
Iterator Begin()
{
size_t hashi = 0;
while (!_tables[hashi])
{
hashi++;
}
return Iterator(_tables[hashi], this);
}
Iterator End()
{
return Iterator(nullptr, this);
}
ConstIterator Begin()const
{
size_t hashi = 0;
while (!_tables[hashi])
{
hashi++;
}
return ConstIterator(_tables[hashi], this);
}
ConstIterator End()const
{
return ConstIterator(nullptr, this);
}
//...
};
3. 实现unordered_set
完整代码:
cpp
#include"Hash.h"
namespace yfr
{
template<class K,class Hash = HashKey<K>>
class unodered_set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
//typedef typename hash_bucket::HashTable<K, K, SetKeyOfT, Hash>::Iterator Iterator;
//typedef typename hash_bucket::HashTable<K, K, SetKeyOfT, Hash>::ConstIterator ConstIterator;
using Iterator = typename hash_bucket::HashTable <K, K, SetKeyOfT, Hash>::Iterator;
using ConstIterator = typename hash_bucket::HashTable <K, K, SetKeyOfT, Hash>::ConstIterator;
Iterator begin()
{
return _ht.Begin();
}
Iterator end()
{
return _ht.End();
}
ConstIterator begin() const
{
return _ht.Begin();
}
ConstIterator end() const
{
return _ht.End();
}
bool insert(const K&key)
{
return _ht.Insert(key);
}
hash_bucket::HashNode<K>* find(const K& key)
{
return _ht.Find(key);
}
bool erase(const K& key)
{
return _ht.Erase(key);
}
private:
hash_bucket::HashTable<K, K, SetKeyOfT,Hash> _ht;
};
}
4. 实现unordered_map
完整代码:
cpp
namespace yfr
{
template<class K,class V,class Hash= HashKey<K>>
class undered_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, Hash>::Iterator Iterator;
typedef typename hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT, Hash>::ConstIterator ConstIterator;
Iterator begin()
{
return _ht.Begin();
}
Iterator end()
{
return _ht.End();
}
ConstIterator begin() const
{
return _ht.Begin();
}
ConstIterator end() const
{
return _ht.End();
}
bool insert(const pair<K, V>& p)
{
return _ht.Insert(p);
}
hash_bucket::HashNode<pair<K,V>>* find(const K& key)
{
return _ht.Find(key);
}
bool erase(const K& key)
{
return _ht.Erase(key);
}
private:
hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT, Hash> _ht;
};
}
5. 完整代码
各位可以去这里看完整代码:unodered_xxx/unodered_xxx/Hash.h · 大白同学/C++进阶学习 - Gitee.com