哈希表封装myunordered_map和myunordered_set
1.set和map框架
//unorderedset.h
namespace smc
{template<class K, class Hash = HashFunc<K>>class unordered_set{struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:bool insert(const K& key){return _ht.Insert(key);}private:hash_bucket::HashTable<K, K, SetKeyOfT, Hash> _ht;};
}
// unorderedMap.h
namespace smc
{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:bool insert(const pair<K, V>& kv){return _ht.Insert(kv);}private:hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT, Hash> _ht;};
}
2.支持iterator的实现
2.1 思路分析
- 哈希表的迭代器是单向迭代器
- 难点是operator++的实现。iterator中有一个指向结点的指针,如果当前桶下面还有结点, 则结点的指针指向下一个结点即可。如果当前桶走完了,则需要想办法计算找到下一个桶。
- 所以迭代器的构造需要一个结点指针+一个哈希表对象指针,方便计算并指向哈希桶一个位置,依次往后找下⼀个不为空的桶即可
- begin()返回第一个桶中第一个节点指针构造的迭代器,end()返回迭代器可以用空表示
- unordered_set的iterator也不支持修改,把unordered_set的第二个模板参数改成const K即可,
- unordered_map的iterator不支持修改key但是可以修改value,我们把unordered_map的第二
- 个模板参数pair的第一个参数改成const K即可
//HashTable.h template<class T> struct HashNode {T _data;HashNode<T>* _next;HashNode(const T& data):_data(data), _next(nullptr){} };//前置声明 template<class K, class T, class KeyOfT, class Hash> class HashTable;template<class K, class T, class KeyOfT, class Hash> struct __HTIterator {typedef HashNode<T> Node;typedef HashTable<K, T, KeyOfT, Hash> HT;typedef __HTIterator<K, T, KeyOfT, Hash> Self;Node* _node;HT* _ht;__HTIterator(Node* node,HT* ht):_node(node),_ht(ht){}T& operator*(){return _node->_data;}T* operator&(){return &(_node->_data);}bool operator!=(const Self& s){return s._node != _node;}bool operator==(const Self& s){return s._node == _node;}Self& operator++(){if (_node){// 当前桶还有节点_node = _node->_next;}else{//找下一个不为空的桶 Hash hs;KeyOfT kot;size_t hashi = hs(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 =HashFunc<K> > class HashTable {template<class K, class T, class KeyOfT, class Hash>friend struct __HTIterator;typedef HashNode<T> Node; public:typedef __HTIterator<K, T, KeyOfT, Hash> Iterator;Iterator Begin(){for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];if (cur){return Iterator(cur, this);}}return End();}Iterator End(){return Iterator(nullptr, this);}HashTable(){_tables.resize(__stl_next_prime(1), nullptr);}~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 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;}bool Insert(const T& data){KeyOfT kot;if (Find(kot(data)))return false;Hash hs;if (_n == _tables.size()){size_t newSize = __stl_next_prime(_tables.size() + 1);vector<Node*> newtables(newSize, nullptr);// 遍历旧表,把旧表的节点挪动到新表for (size_t i = 0; i < _tables.size(); i++){Node* cur = _tables[i];while (cur){Node* next = cur->_next;// cur头插到新表size_t hashi =hs( kot(cur->_data) )% newSize;cur->_next = newtables[hashi];newtables[hashi] = cur;cur = next;}_tables[i] = nullptr;}_tables.swap(newtables);}size_t hashi =hs(kot(data)) % _tables.size();Node* newnode = new Node(data);// 头插到桶里面newnode->_next = _tables[hashi];_tables[hashi] = newnode;_n++;return true;}Node* Find(const K& key){KeyOfT kot;Hash hs;size_t hashi = hs(key) % _tables.size();Node* cur = _tables[hashi];while (cur){if (kot(cur->_data) == key)return cur;cur = cur->_next;}return nullptr;}bool Erase(const K& key){KeyOfT kot;Hash hs;size_t hashi =hs( key) % _tables.size();Node* cur = _tables[hashi];Node* prev = nullptr;while (cur){if (kot(cur->_data) == key){// 头删if (prev == nullptr){_tables[hashi] = cur->_next;}else{prev->_next = cur->_next;}delete cur;--_n;return true;}prev = cur;cur = cur->_next;}return false;} private:vector<Node*> _tables;// 指针数组 size_t _n = 0; // 表中存储数据个数 };
此处实现迭代器需要访问哈希表中私有的_ables,则可以把Iterator实现为哈希表的友元函数类模板成为友元函数需要加上模板参数
3. map支持[]
unordered_map要支持[]主要需要修改insert返回值支持,修改HashTable中的insert返回值为
4.代码实现
哈希封装