思路和用红黑树封装map和set类似
哈希表的结构如下所示
template<class K, class T,class KOfT, class Hash = HashFun<K>> class HashBucket { private: vector<Node*> _bucket; size_t _n = 0; // 表中存储的数据个数 };
K为键值,T为节点里存的数据的类型,KOfT是为了让unordered_map取出key值的仿函数,Hash是将K值转化成无符号整形的仿函数,默认支持能强转成整形,对string做了特化。
哈希表的迭代器
迭代器的结构如下:
template<class T, class KOfT,class Ref,class Ptr, class Hash> class HashBucket_iterator { private: Node* _node; const vector<Node*>* _bucket; };
T为节点里存的数据的类型,KOfT是为了让unordered_map取出key值的仿函数,Ref为T的引用或者const引用,Ptr为T的指针或者const指针,为了一份模板可以同时实例化出iterator和const_iterator。Hash是将K值转化成无符号整形的仿函数,需要靠HashBucket传参。
成员变量:
_node为当前结点的指针
_bucket为哈希表的指针,为了跨单个桶时,能找到下一个桶。
迭代器的operator++实现:
思路:若当前节点的next不为空,当前单链表没有走完,_node = _node->_next,返回;
若当前节点的next为空,就要根据当前节点的key转整形计算出哈希值,从当前节点的下一个开始遍历vector,直到头结点指针不为空或者vector遍历完了,头节点指针不为空,让_node等于头指针,返回;若vector遍历完了,就让_node指向空(即end())。
Self& operator++() { assert(_node); //下一个为空,已经是单链表的尾了 if (_node->_next == nullptr) { KOfT kot; size_t hashi = kot(_node->_data) % (*_bucket).size(); ++hashi; //找下一个不为空的头 while (hashi < (*_bucket).size()) { if ((*_bucket)[hashi] != nullptr) { _node = (*_bucket)[hashi]; return *this; } ++hashi; } //vector被遍历完了 _node = nullptr; return *this; } else { _node = _node->_next; } return *this; }
unordered_map的operator[]实现:
V& operator[](const K& key) { pair<iterator, bool> ret = insert({ key,V() }); //iterator->返回data* -> second,省略了一个-> //返回V& return ret.first->second; }
以下是完整代码:
HashTable.h
#pragma once using namespace std; #include<vector> #include<string> #include<algorithm> #include<assert.h> 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 }; inline unsigned long __stl_next_prime(unsigned long n) { 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; } template<class K> struct HashFun { size_t operator()(const K& key) { return static_cast<size_t>(key); } }; template<> struct HashFun<string> { size_t operator()(const string& key) { size_t ret = 0; for (auto e : key) { ret += e; ret *= 131; } return ret; } }; template<class T> struct ListNode { ListNode(const T& data) :_data(data) , _next(nullptr) {} T _data; ListNode<T>* _next; }; template<class T, class KOfT,class Ref,class Ptr, class Hash> class HashBucket_iterator { private: typedef typename ListNode<T> Node; typedef typename HashBucket_iterator<T, KOfT, Ref, Ptr, Hash> Self; public: HashBucket_iterator(Node* node,const vector<Node*>* bucket) :_node(node) ,_bucket(bucket) {} Ref operator*() { return _node->_data; } Ptr operator->() { return &_node->_data; } bool operator!=(const Self& hbit) { return _node != hbit._node; } bool operator==(const Self& hbit) { return _node == hbit._node; } Self& operator++() { assert(_node); //下一个为空,已经是单链表的尾了 if (_node->_next == nullptr) { KOfT kot; size_t hashi = kot(_node->_data) % (*_bucket).size(); ++hashi; //找下一个不为空的头 while (hashi < (*_bucket).size()) { if ((*_bucket)[hashi] != nullptr) { _node = (*_bucket)[hashi]; return *this; } ++hashi; } //vector被遍历完了 _node = nullptr; return *this; } else { _node = _node->_next; } return *this; } private: Node* _node; const vector<Node*>* _bucket; }; template<class K, class T,class KOfT, class Hash = HashFun<K>> class HashBucket { private: typedef typename ListNode<T> Node; public: typedef typename HashBucket_iterator<T, KOfT, T&, T*, Hash> Iterator; typedef typename HashBucket_iterator<T, KOfT, const T&, const T*, Hash> ConstIterator; public: HashBucket(const size_t sz = 11) { _bucket.resize(sz); } ~HashBucket() { for (size_t i = 0; i < _bucket.size(); ++i) { if (_bucket[i] != nullptr) { Node* cur = _bucket[i]; Node* next = cur->_next; while (cur) { delete cur; cur = next; if (cur) next = cur->_next; } } } } Iterator Begin() { Node* begin = nullptr; size_t curi = 0; while (curi<_bucket.size()) { if (_bucket[curi]) { begin = _bucket[curi]; break; } ++curi; } return Iterator(begin,&_bucket); } Iterator End() { return Iterator(nullptr, &_bucket); } pair<Iterator,bool> Insert(const T& data) { KOfT kot; Iterator it = Find(kot(data)); //找到了,插入失败 if (it != End()) return { it,false }; //负载因子等于1时,扩容 if (_n == _bucket.size()) { //思路:将原哈希桶的节点拿下来,插入到新的桶 vector<Node*> newbucket; newbucket.resize(__stl_next_prime(_bucket.size()) + 1); size_t newsz = newbucket.size(); Hash hash; //按原桶的vector下标遍历 for (size_t i = 0; i < _bucket.size(); ++i) { if (_bucket[i] != nullptr) { Node* cur = _bucket[i]; Node* next = cur->_next; //cur即为当前遍历的节点 // 将其 头插 到新的哈希桶中 while (cur) { size_t hashi = hash(kot(cur->_data)) % newsz; //头插,cur head,cur成为新的头 cur->_next = newbucket[hashi]; newbucket[hashi] = cur; //迭代 cur = next; if (cur) next = cur->_next; } } _bucket[i] = nullptr; } _bucket.swap(newbucket); } Hash hash; size_t hashi = hash(kot(data)) % _bucket.size(); Node* newnode = new Node(data); //头插,newnode head,newnode成为新的头 newnode->_next = _bucket[hashi]; _bucket[hashi] = newnode; ++_n; return { { newnode,&_bucket }, false }; } Iterator Find(const K& key) { Hash hash; KOfT kot; size_t hashi = hash(key) % _bucket.size(); Node* cur = _bucket[hashi]; while (cur) { if (kot(cur->_data) == key) { return { cur,&_bucket }; } cur = cur->_next; } return { nullptr,&_bucket }; } bool Erase(const K& key) { Hash hash; KOfT kot; size_t hashi = hash(key) % _bucket.size(); Node* cur = _bucket[hashi]; //cur为头结点的指针 if (cur == nullptr) return false; //头删,_bucket[hashi](cur) curNext if (kot(cur->_data) == key) { _bucket[hashi] = cur->_next; delete cur; --_n; return true; } //中间删除 else { Node* prev = nullptr; //prev cur curNext while (cur && kot(cur->_data) != key) { prev = cur; cur = cur->_next; } if (cur == nullptr) { return false; } else { prev->_next = cur->_next; delete cur; --_n; return true; } } } private: vector<Node*> _bucket; size_t _n = 0; // 表中存储的数据个数 };
MyUnorderedMap.h
#pragma once #include "HashTable.h" namespace quiteSix { template<class K,class V> class unordered_map { private: struct unordered_map_KeyOfT { const K& operator()(const pair<const K, V>& data) const { return data.first; } }; private: typedef typename HashBucket<K, pair<const K, V>, unordered_map_KeyOfT> hashbucket; typedef typename hashbucket::Iterator iterator; typedef typename hashbucket::ConstIterator const_iterator; public: iterator begin() { return _hb.Begin(); } iterator end() { return _hb.End(); } pair<iterator, bool> insert(const pair<const K, V>& data) { return _hb.Insert(data); } iterator find(const K& key) { return _hb.Find(key); } bool erase(const K& key) { return _hb.Erase(key); } V& operator[](const K& key) { pair<iterator, bool> ret = insert({ key,V() }); //iterator->返回data* -> second,省略了一个-> //返回V& return ret.first->second; } private: hashbucket _hb; }; }
MyUnorderedSet.h
#pragma once #include "HashTable.h" namespace quiteSix { template<class K> class unordered_set { private: struct unordered_set_KeyOfT { const K& operator()(const K& data) const { return data; } }; private: typedef typename HashBucket<K, const K, unordered_set_KeyOfT> hashbucket; typedef typename hashbucket::Iterator iterator; typedef typename hashbucket::ConstIterator const_iterator; public: iterator begin() { return _hb.Begin(); } iterator end() { return _hb.End(); } pair<iterator, bool> insert(const K& data) { return _hb.Insert(data); } iterator find(const K& key) { return _hb.Find(key); } bool erase(const K& key) { return _hb.Erase(key); } private: hashbucket _hb; }; }