文章目录
- 0. 前言
- 1. 改造哈希表
* - 1.1 哈希表节点的定义
- 1.2 哈希表中的迭代器
– - 1.3 仿函数
- 1.4 哈希表整体改造完成后的代码
- 2. 封装实现unordered_map
- 3. 封装实现unordered_set
- 4. 测试案例
-
前言
-
改造哈希表
链接:c++哈希(哈希表开散列实现的哈希表)
上面那篇文章,我们了解了哈希表的底层结构并模拟实现哈希表数据插入和删除。
这篇文章我们利用哈希表装实现unordered_map和unordered_set。
1.1 哈希表节点的定义
- 因为我们要利用一颗树封装实现unordered_map和unordered_set,所以我们不能写死。
- 怎么做?那看下面代码。
template<class T>
struct HashNode
{
T _data;
HashNode<T>* _next;
HashNode(const T& data)
:_data(data)
,_next(nullptr)
{}
};
- 我们把模板template
- 看到这里uu们就很疑惑,那怎么区别那?我们就要借助仿函数(KeyOfT )-> 支持取出T对象中key的值。
1.2 哈希表中的迭代器
- 迭代器大致框架跟利用红黑树封装map和set相同;区别我们上一篇文章实现的哈希表每一个位置是一个桶(单链表);我们只用模拟实现后置加加操作即可。
1.2.1 模拟实现后置加加的方法
- 思路:加加分为俩种
–- 当前桶位置找下一个节点。
– - 找下一个哈希桶起始位置。
- 当前桶位置找下一个节点。
typedef __HashIterator<K, T, Hash, KeyOfT> Self;
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
Hash hash;
KeyOfT kot;
size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
++i;
for (; i < _pht->_tables.size(); ++i)
{
if (_pht->_tables[i])
{
_node = _pht->_tables[i];
break;
}
}
if (i == _pht->_tables.size())
{
_node = nullptr;
}
}
1.2.2 哈希表迭代器代码
- 注意:我们实现迭代器还要访问原来哈希表类的成员(私有成员需要把迭代器变为哈希表的友元,后面代码会写)
template<class K, class T, class Hash, class KeyOfT>
class HashTable;
template<class K, class T, class Hash, class KeyOfT>
struct __HashIterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, Hash, KeyOfT> HT;
typedef __HashIterator<K, T, Hash, KeyOfT> Self;
Node* _node;
HT* _pht;
__HashIterator(Node* node, HT* pht)
:_node(node)
, _pht(pht)
{}
T& operator*()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
Hash hash;
KeyOfT kot;
size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
++i;
for (; i < _pht->_tables.size(); ++i)
{
if (_pht->_tables[i])
{
_node = _pht->_tables[i];
break;
}
}
if (i == _pht->_tables.size())
{
_node = nullptr;
}
}
return *this;
}
bool operator!=(const Self& s) const
{
return _node != s._node;
}
bool operator==(const Self& s) const
{
return _node == s._node;
}
};
1.3 仿函数
- 除了上章比较用的仿函数Hash = HashFunc;此章我们还需要一个区分unordered_map和unordered_set的仿函数。
- 因为map是pair
struct MapKeyOfT
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
struct MapKeyOfT
{
const K& operator()(const K& val)
{
return val;
}
};
实现过程就在上图代码里了。
1.4 哈希表整体改造完成后的代码
namespace HashBucket
{
template<class T>
struct HashNode
{
T _data;
HashNode<T>* _next;
HashNode(const T& data)
:_data(data)
,_next(nullptr)
{}
};
template<class K, class T, class Hash, class KeyOfT>
class HashTable;
template<class K, class T, class Hash, class KeyOfT>
struct __HashIterator
{
typedef HashNode<T> Node;
typedef HashTable<K, T, Hash, KeyOfT> HT;
typedef __HashIterator<K, T, Hash, KeyOfT> Self;
Node* _node;
HT* _pht;
__HashIterator(Node* node, HT* pht)
:_node(node)
, _pht(pht)
{}
T& operator*()
{
return _node->_data;
}
T* operator->()
{
return &_node->_data;
}
Self& operator++()
{
if (_node->_next)
{
_node = _node->_next;
}
else
{
Hash hash;
KeyOfT kot;
size_t i = hash(kot(_node->_data)) % _pht->_tables.size();
++i;
for (; i < _pht->_tables.size(); ++i)
{
if (_pht->_tables[i])
{
_node = _pht->_tables[i];
break;
}
}
if (i == _pht->_tables.size())
{
_node = nullptr;
}
}
return *this;
}
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 Hash, class KeyOfT>
class HashTable
{
typedef HashNode<T> Node;
template<class K, class T, class Hash, class KeyOfT>
friend struct __HashIterator;
public:
typedef __HashIterator<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);
}
~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;
}
}
inline size_t __stl_next_prime(size_t n)
{
static const size_t __stl_num_primes = 28;
static const size_t __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
};
for (size_t i = 0; i < __stl_num_primes; ++i)
{
if (__stl_prime_list[i] > n)
{
return __stl_prime_list[i];
}
}
return -1;
}
pair<iterator, bool> Insert(const T& data)
{
KeyOfT kot;
Hash hash;
iterator ret = Find(kot(data));
if (ret != end())
{
return make_pair(ret, false);
}
if (_tables.size() == _size)
{
vector<Node*> newTables;
newTables.resize(__stl_next_prime(_tables.size()), nullptr);
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)) % newTables.size();
cur->_next = newTables[hashi];
newTables[hashi] = cur;
cur = next;
}
_tables[i] = nullptr;
}
_tables.swap(newTables);
}
size_t hashi = hash(kot(data)) % _tables.size();
Node * newNode = new Node(data);
newNode->_next = _tables[hashi];
_tables[hashi] = newNode;
++_size;
return make_pair(iterator(newNode, this), false);
}
iterator Find(const K& key)
{
if (Empty())
{
return end();
}
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 Empty() const
{
return _size == 0;
}
bool Erase(const K& key)
{
if (Empty())
{
return false;
}
Hash hash;
int hashi = hash(key) % _tables.size();
Node* cur = _tables[hashi];
Node* prev = nullptr;
while (cur)
{
if (key == kot(cur->_data))
{
if (prev)
{
prev->_next = cur->_next;
}
else
{
_tables[hashi] = cur->_next;
}
delete cur;
--_size;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
size_t Size()
{
return _size;
}
size_t TablesSize()
{
return _tables.size();
}
size_t BucketNum()
{
size_t num = 0;
for (size_t i = 0; i < _tables.size(); ++i)
{
if (_tables[i])
{
++num;
}
}
return num;
}
size_t MaxBucketLenth()
{
size_t maxLen = 0;
for (size_t i = 0; i < _tables.size(); ++i)
{
size_t len = 0;
Node* cur = _tables[i];
while (cur)
{
++len;
cur = cur->_next;
}
if (len > maxLen)
{
maxLen = len;
}
}
return maxLen;
}
private:
vector<Node*> _tables;
size_t _size = 0;
};
}
-
封装实现unordered_map
-
注意:typename的使用–我们要取取类里面的类型而不是变量(例如:类的静态变量)需要说明。
#pragma once
#include "HashTable.h"
namespace Ding
{
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 HashBucket::HashTable<K, pair<K, V>, Hash, MapKeyOfT> ::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
pair<iterator, bool> insert(const pair<K, V>& kv)
{
return _ht.Insert(kv);
}
V& operator[](const K& key)
{
pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
return ret.first->second;
}
private:
HashBucket::HashTable<K, pair<K, V>, Hash, MapKeyOfT> _ht;
};
-
封装实现unordered_set
-
注意:typename的使用–我们要取取类里面的类型而不是变量(例如:类的静态变量)需要说明。
#pragma once
#include "HashTable.h"
namespace Ding
{
template<class K, class Hash = HashFunc<K>>
class unordered_set
{
struct MapKeyOfT
{
const K& operator()(const K& val)
{
return val;
}
};
public:
typedef typename HashBucket::HashTable<K, K, Hash, MapKeyOfT> ::iterator iterator;
iterator begin()
{
return _ht.begin();
}
iterator end()
{
return _ht.end();
}
pair<iterator, bool> insert(const K& val)
{
return _ht.Insert(val);
}
private:
HashBucket::HashTable<K, K, Hash, MapKeyOfT> _ht;
};
- 测试案例
/unordered_map/
void test_map()
{
unordered_map<string, string> dict;
dict.insert(make_pair("sort", "排序"));
dict.insert(make_pair("right", "右边"));
dict.insert(make_pair("left", "左边"));
unordered_map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
unordered_map<string, int> countMap;
string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
for (auto e : arr)
{
countMap[e]++;
}
for (auto& kv : countMap)
{
cout << kv.first << ":" << kv.second << endl;
}
}
}
/unordered_set/
void test_set()
{
unordered_set<int> s;
s.insert(2);
s.insert(3);
s.insert(1);
s.insert(2);
s.insert(5);
unordered_set<int>::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
}
- 测试结果
Original: https://blog.csdn.net/Dingyuan0/article/details/127816725
Author: 潜水少年请求出战
Title: _cpp利用哈希封装实现unordered_map和unordered_set
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/654764/
转载文章受原作者版权保护。转载请注明原作者出处!