赞
踩
针对上文中所模拟实现的开散列,进行以下两点改造:
// K:关键码类型
// V: 不同容器V的类型不同,如果是unordered_map,V代表一个键值对,如果是unordered_set,V 为 K
// KeyOfValue: 因为V的类型不同,通过value取key的方式就不同,详细见unordered_map/set的实现
// HF: 哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将Key转换为整形数字才能取模
template<class K, class V, class KeyOfValue, class HF = DefHashF<T> >
class HashBucket;
++a、a++、!=、==、begin()、end()
等等,以及插入、删除、查找的返回值需要改造为相应的迭代器等操作。以下代码多处已经过注释,已经过测试,未发现大漏洞,基本满足实现要求。若有疑问的话希望能看看上篇文章的思路,讲解的很清楚,或是在下留言即可。
参见代码如下:
// HashBucket.h #pragma once #include <vector> using namespace std; template<class T> class HashBucketNode { T m_val; HashBucketNode<T> * m_next; HashBucketNode(const T & val = T()) : m_val(val), m_next(nullptr) {} template<class K, class V, class KeyofValue, class HF> friend class HashBucket; }; class dealInt { public: int operator()(int n) { return n; } }; template<class K, class V, class KeyofValue, class HF = dealInt> class HashBucket { vector<HashBucketNode<V> *> m_data; size_t m_size; static long long s_m_primeTable[30]; int m_primePos; public: HashBucket(size_t capacity = s_m_primeTable[0]) : m_data(capacity, nullptr), m_size(0), m_primePos(0) {} // 内部类写iterator // 内部类不需要写template<class K, class V, class KeyofValue, class HF = dealInt> // 会继承外部类的一切 class iterator { public: // 将开散列看作二维数组结构的话,我们需要使用迭代器确定横纵坐标 // 1.即vector内的桶的位置信息需要确定,作为横坐标这个迭代器, // 主要方便++操作,若对链表最后一个元素++,则找下一个不为空的vector元素位置即可 // 2.在该桶中即链表中的元素位置信息需要确定,作为纵坐标 HashBucket<K, V, KeyofValue, HF> * m_hb; HashBucketNode<V> * m_node; // 初始化一个桶,才能够进行使用 iterator(HashBucketNode<V> * node = nullptr, HashBucket<K, V, KeyofValue, HF> * hbpos = nullptr): m_node(node), m_hb(hbpos) {} iterator(const iterator & it) : m_node(it.m_node), m_hb(it.m_hb) {} // 迭代器 V& operator*() { return m_node->m_val; } V* operator->() { return &m_node->m_val; } // 前置++ iterator operator++() { // 提前保存m_val,若m_node为最后一个数据 // 则++后出现空值的情况 int val = m_node->m_val; m_node = m_node->m_next; // 若m_node为空 if (!m_node) { // 得到下一个桶的位置 // 如果node为最后一个桶的最后一个元素 // +1后不会进入for循环,返回空即可,这样做是合理的 // 否则针对最后一个桶中的最后一个元素进行++的情况,极易返回什么都不做的m_node int bucketno = m_hb->hashFunc(KeyofValue()(val)) + 1; for (; bucketno < m_hb->capacity(); bucketno++) { // 如果当前桶的位置不为空 if (m_hb->m_data[bucketno]) { m_node = m_hb->m_data[bucketno]; break; } } } return *this; } // 后置++ iterator operator++(int) { // 调用拷贝构造,保存副本 iterator<K, V, KeyofValue, HF> tmp = *this; // 调用前置++即可 ++(*this); // 返回副本即可 return tmp; } // == != 均为双目运算符,第一个参数为this指针 // 仅需传入第二个参数即可,并且加两个const,不希望两者改变 bool operator==(const iterator & data) const { return m_node == data.m_node && m_hb == data.m_hb; } bool operator!=(const iterator & data) const { return m_node != data.m_node || m_hb != data.m_hb; } }; private: int hashFunc(const K & key) { HF func; return func(key) % capacity(); } void checkCapacity() { if (m_size == capacity()) { int mcapa = capacity(); vector<HashBucketNode<V> *> tmp(s_m_primeTable[++m_primePos], nullptr); m_data.swap(tmp); m_size = 0; int i; HashBucketNode<V> * cur; for (i = 0; i < mcapa; i++) { for (cur = tmp[i]; cur; cur = cur->m_next) { insert(cur->m_val); } } } } public: // 返回第一个迭代器 iterator begin() { // 从vector第一个位置开始找即可 int bucketno = 0; for (; bucketno < capacity(); bucketno++) { if (m_data[bucketno]) { return iterator(m_data[bucketno], this); } } return iterator(nullptr, this); } iterator end() { return iterator(nullptr, this); } iterator insert(const V & val) { checkCapacity(); int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * tmp; if (m_data[hashnum]) { for (tmp = m_data[hashnum]; tmp; tmp = tmp->m_next) { if (tmp->m_val == val) { // 代表插入失败 return end(); } } } tmp = new HashBucketNode<V>(val); tmp->m_next = m_data[hashnum]; m_data[hashnum] = tmp; m_size++; // 返回插入迭代器,当前位置,桶的位置 return iterator(m_data[hashnum], this); } iterator erase(const V & val) { int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * tmp; if (!m_data[hashnum]) { // 当前桶不存在,删除失败,返回end()即可 return end(); } // 当前桶存在,查看是否为头删 if (m_data[hashnum]->m_val == val) { // 保存头结点的副本res,++res找到待返回的下一个节点 iterator res(m_data[hashnum], this); ++res; // 进行头删 tmp = m_data[hashnum]; m_data[hashnum] = tmp->m_next; delete tmp; // 返回下一个节点即可 m_size--; return res; } // 执行后删,道理如同头删操作 else { for (tmp = m_data[hashnum]; tmp->m_next; tmp = tmp->m_next) { if (tmp->m_next->m_val == val) { iterator res(tmp->m_next, this); ++res; HashBucketNode<V> * cur; cur = tmp->m_next; tmp->m_next = cur->m_next; delete cur; m_size--; return res; } } return end(); } } iterator find(const V & val) { int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * cur; for (cur = m_data[hashnum]; cur; cur = cur->m_next) { if (cur->m_val == val) { return iterator(cur, this); } } return iterator(nullptr, this); } void clear() { HashBucketNode<V> * tmp; for (auto & head : m_data) { while (head) { tmp = head; head = head->m_next; delete tmp; } } m_size = 0; } size_t capacity() { return s_m_primeTable[m_primePos]; } }; template<class K, class V, class KeyofValue, class HF> long long HashBucket<K, V, KeyofValue, HF>::s_m_primeTable[30] = { 11, 23, 47, 89, 179, 353, 709, 1409, 2819, 5639, 11273, 22531, 45061, 90121, 180233, 360457, 720899, 1441807, 2883593, 5767169, 11534351, 23068673, 46137359, 92274737, 184549429, 369098771, 738197549, 1476395029, 2952790016u, 4294967291u };
有了上面 "HashBucket.h"
,仅需简单改造即可
unordered_map
中存储的是 pair<K, V>
的键值对,K
为 key
的类型, V
为 value
的类型,HF
哈希函数类型 unordered_map
在实现时,只需将 hashbucket
中的接口重新封装即可。
尤其注意下 unordered_map
各类函数的返回值可能与想象的有所不同,例如其 insert
会返回 pair<iterator, bool>
,这个问题得进行修改,在 "HashBucket.h"
需要将 insert
函数进行改造。
参见代码如下:
pair<iterator, bool> insert(const V & val) { checkCapacity(); int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * tmp; if (m_data[hashnum]) { for (tmp = m_data[hashnum]; tmp; tmp = tmp->m_next) { if (tmp->m_val == val) { pair<iterator, bool> pairtmp; pairtmp.first = end(); pairtmp.second = false; return pairtmp; } } } tmp = new HashBucketNode<V>(val); tmp->m_next = m_data[hashnum]; m_data[hashnum] = tmp; m_size++; pair<iterator, bool> pairtmp; iterator it(m_data[hashnum], this); pairtmp.first = it; pairtmp.second = true; return pairtmp; }
count
函数判断某一个 key
值是否在哈希表里。在 "HashBucket.h"
需要将 count
函数进行添加。
参见代码如下:
size_t count(const K & kv)
{
int bucketno = hashFunc(kv);
HashBucketNode<V> * cur;
for (cur = m_data[bucketno]; cur; cur = cur->m_next)
{
if (KeyofValue()(cur->m_val) == kv)
{
return 1;
}
}
return 0;
}
bucketCount
返回桶的个数。在 "HashBucket.h"
需要将 bucketCount
函数进行添加。
size_t bucketCount()
{
return capacity();
}
bucketSize
返回某个桶中的元素个数。在 "HashBucket.h"
需要将 bucketSize
函数进行添加。
size_t bucketSize(size_t bucketno)
{
HashBucketNode<V> * cur;
int count = 0;
for (cur = m_data[bucketno]; cur; cur = cur->next)
{
count++;
}
return count;
}
operator[ ]
是 map、unordered_map
的一大特色,在此一定要理解其作用。有些代码用中括号来查找 map
,其实在 map
中,中括号已经被重载为有不存在即插入的功能。于是如果查找的 key
不存在,则 map
中会增加很多垃圾数据。
参见代码如下:
// 写法1 // 传进K返回V,[ ]传入插入K值,返回对应的V值 // 看到有些代码,用中括号来查找map, // 其实在map中,中括号已经被重载为有不存在即插入的功能。 // 于是如果查找的key不存在,则map中会增加很多垃圾数据。 V& operator[](const K & key) { // pair<K, V>(key, V()) 中V()为任意值,最后需要将其返回,传入V的构造函数最为保险 pair<iterator, bool> ptmp = m_hb.insert(pair<K, V>(key, V())); iterator itmp = ptmp.first; // return itmp->second; return (*itmp).second; } // 写法2 // 一行简洁流 不建议,可读性太差 // 在方法一中并不一定会创建临时变量,编译器会进行优化 const V& operator[](const K & key) const { return (*(m_hb.insert(pair<K, V>(key, V()))).first).second; }
修改后的 "HashBucket.h"
参见代码如下:
#pragma once #include <vector> using namespace std; template<class T> class HashBucketNode { T m_val; HashBucketNode<T> * m_next; HashBucketNode(const T & val = T()) : m_val(val), m_next(nullptr) {} template<class K, class V, class KeyofValue, class HF> friend class HashBucket; }; class dealInt { public: int operator()(int n) { return n; } }; template<class K, class V, class KeyofValue, class HF = dealInt> class HashBucket { vector<HashBucketNode<V> *> m_data; size_t m_size; static long long s_m_primeTable[30]; int m_primePos; public: HashBucket(size_t capacity = s_m_primeTable[0]) : m_data(capacity, nullptr), m_size(0), m_primePos(0) {} ~HashBucket() { clear(); } class iterator { public: HashBucket<K, V, KeyofValue, HF> * m_hb; HashBucketNode<V> * m_node; iterator(HashBucketNode<V> * node = nullptr, HashBucket<K, V, KeyofValue, HF> * hbpos = nullptr) : m_node(node), m_hb(hbpos) {} iterator(const iterator & it) : m_node(it.m_node), m_hb(it.m_hb) {} V& operator*() { return m_node->m_val; } V* operator->() { return &m_node->m_val; } iterator operator++() { V val = m_node->m_val; m_node = m_node->m_next; if (!m_node) { int bucketno = m_hb->hashFunc(KeyofValue()(val)) + 1; for (; bucketno < m_hb->capacity(); bucketno++) { if (m_hb->m_data[bucketno]) { m_node = m_hb->m_data[bucketno]; break; } } } return *this; } iterator operator++(int) { iterator<K, V, KeyofValue, HF> tmp = *this; ++(*this); return tmp; } bool operator==(const iterator & data) const { return m_node == data.m_node && m_hb == data.m_hb; } bool operator!=(const iterator & data) const { return m_node != data.m_node || m_hb != data.m_hb; } }; private: int hashFunc(const K & key) { HF func; return func(key) % capacity(); } void checkCapacity() { if (m_size == capacity()) { int mcapa = capacity(); vector<HashBucketNode<V> *> tmp(s_m_primeTable[++m_primePos], nullptr); m_data.swap(tmp); m_size = 0; int i; HashBucketNode<V> * cur; for (i = 0; i < mcapa; i++) { for (cur = tmp[i]; cur; cur = cur->m_next) { insert(cur->m_val); } } } } public: iterator begin() { int bucketno = 0; for (; bucketno < capacity(); bucketno++) { if (m_data[bucketno]) { return iterator(m_data[bucketno], this); } } return iterator(nullptr, this); } iterator end() { return iterator(nullptr, this); } pair<iterator, bool> insert(const V & val) { checkCapacity(); int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * tmp; if (m_data[hashnum]) { for (tmp = m_data[hashnum]; tmp; tmp = tmp->m_next) { if (tmp->m_val == val) { pair<iterator, bool> pairtmp; pairtmp.first = end(); pairtmp.second = false; return pairtmp; } } } tmp = new HashBucketNode<V>(val); tmp->m_next = m_data[hashnum]; m_data[hashnum] = tmp; m_size++; pair<iterator, bool> pairtmp; iterator it(m_data[hashnum], this); pairtmp.first = it; pairtmp.second = true; return pairtmp; } iterator erase(const V & val) { int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * tmp; if (!m_data[hashnum]) { return end(); } if (m_data[hashnum]->m_val == val) { iterator res(m_data[hashnum], this); ++res; tmp = m_data[hashnum]; m_data[hashnum] = tmp->m_next; delete tmp; m_size--; return res; } else { for (tmp = m_data[hashnum]; tmp->m_next; tmp = tmp->m_next) { if (tmp->m_next->m_val == val) { iterator res(tmp->m_next, this); ++res; HashBucketNode<V> * cur; cur = tmp->m_next; tmp->m_next = cur->m_next; delete cur; m_size--; return res; } } return end(); } } iterator find(const V & val) { int hashnum = hashFunc(KeyofValue()(val)); HashBucketNode<V> * cur; for (cur = m_data[hashnum]; cur; cur = cur->m_next) { if (cur->m_val == val) { return iterator(cur, this); } } return iterator(nullptr, this); } void clear() { HashBucketNode<V> * tmp; for (auto & head : m_data) { while (head) { tmp = head; head = head->m_next; delete tmp; } } m_size = 0; } size_t capacity() { return s_m_primeTable[m_primePos]; } size_t size() { return m_size; } bool empty() { return m_size == 0; } size_t count(const K & kv) { int bucketno = hashFunc(kv); HashBucketNode<V> * cur; for (cur = m_data[bucketno]; cur; cur = cur->m_next) { if (KeyofValue()(cur->m_val) == kv) { return 1; } } return 0; } size_t bucketCount() { return capacity(); } size_t bucketSize(size_t bucketno) { HashBucketNode<V> * cur; int count = 0; for (cur = m_data[bucketno]; cur; cur = cur->next) { count++; } return count; } /*1、Count 判断某一个Key值是否在哈希表里 2、BucketCount 返回桶的个数 3、BucketSize 返回某个桶中的元素个数*/ }; template<class K, class V, class KeyofValue, class HF> long long HashBucket<K, V, KeyofValue, HF>::s_m_primeTable[30] = { 11, 23, 47, 89, 179, 353, 709, 1409, 2819, 5639, 11273, 22531, 45061, 90121, 180233, 360457, 720899, 1441807, 2883593, 5767169, 11534351, 23068673, 46137359, 92274737, 184549429, 369098771, 738197549, 1476395029, 2952790016u, 4294967291u };
调用 "HashBucket.h"
实现 unordered_map.h
。
参见代码如下:
// unordered_map.h #include "HashBucket.h" template <class K, class V, class HF = dealInt> class unordered_map { class KeyofValue { public: const K& operator()(const pair<K, V> &data) { return data.first; } }; HashBucket<K, pair<K, V>, KeyofValue, HF> m_hb; public: typename typedef HashBucket<K, pair<K, V>, KeyofValue, HF>::iterator iterator; unordered_map(): m_hb() {} ~unordered_map() { m_hb.~HashBucket(); } iterator begin() { return m_hb.begin(); } iterator end() { return m_hb.end(); } iterator size() { return m_hb.size(); } iterator find(const V & val) { return m_hb.find(val); } size_t count(const K & key) { return m_hb.count(key); //透传 } void clear() { return m_hb.clear(); } bool empty() { return m_hb.empty(); } pair<iterator, bool> insert(const pair<K, V> val) { return m_hb.insert(val); } V& operator[](const K & key) { pair<iterator, bool> ptmp = m_hb.insert(pair<K, V>(key, V())); iterator itmp = ptmp.first; return (*itmp).second; } const V& operator[](const K & key) const { return (*(m_hb.insert(pair<K, V>(key, V()))).first).second; } };
关于 unordered
系列的容器,大多都可以经过修改 "HashBucket.h"
模拟实现 ,在此不再赘述了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。