赞
踩
前言:本篇文章继续分享新的容器unordered_map和set。前边我们分享过map和set,其底层为红黑树,而unordered_map和set的底层则为哈希表,因此在unordered_map和set的实现中,我们可以效仿许多在map和set的中就分享过的一些知识,所以在本篇文章中,就不对分享过的知识进行重复讲解。
而unordered_map和set与map和set的区别,即为红黑树和哈希表的区别。
目录
我们所实现的普通哈希表肯定是无法直接拿来作为unordered_map和set的底层代码的,所以我们需要对其进行优化修改,完整代码如下:
- template<class K>
- struct HashFunc
- {
- size_t operator()(const K& key)
- {
- return (size_t)key;
- }
- };
-
- struct HashStringFunc
- {
- size_t operator()(const string& s)
- {
- size_t hash = 0;
- for (auto e : s)
- {
- hash += e;
- }
- return hash;
- }
- };
-
- namespace hash_bucket
- {
- 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 __Iterator
- {
- typedef HashNode<T> Node;
- typedef __Iterator<K, T, KeyOfT, Hash> Self;
- Node* _node;
- HashTable<K, T, KeyOfT, Hash>* _pht;
- __Iterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
- :_node(node)
- ,_pht(pht)
- {}
-
- T& operator*()
- {
- return _node->_data;
- }
- T* operator->()
- {
- return &_node->_data;
- }
- Self& operator++()
- {
- if (_node->_next)
- //当前桶没走完,找到下一个节点
- _node = _node->_next;
- else
- {
- //当前桶走完了,找下一个不为空的桶的第一个节点
- KeyOfT kot;
- Hash hs;
- size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
- i++;
- for (; i < _pht->_tables.size(); i++)
- {
- if (_pht->_tables[i])
- break;
- }
- if (i == _pht->_tables.size())
- //所有桶都走完了,置nullptr
- _node = nullptr;
- else
- _node = _pht->_tables[i];
- }
- return *this;
- }
- bool operator!=(const Self& s)
- {
- return _node != s._node;
- }
- };
-
- template<class K, class T, class KeyOfT, class Hash>
- class HashTable
- {
- typedef HashNode<T> Node;
- public:
- //友元
- template<class K, class T, class KeyOfT, class Hash>
- friend struct __Iterator;
-
- typedef __Iterator<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(10, nullptr);
- _n = 0;
- }
- ~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;
- }
- }
- //插入
- pair<iterator,bool> Insert(const T& data)
- {
- KeyOfT kot;
- Hash hs;
- //判断是否存在
- iterator it = Find(kot(data));
- if (it != end())
- return make_pair(it,false);
- //扩容
- if (_n == _tables.size())
- {
- vector<Node*> newtables(_tables.size() * 2, nullptr);
- for (size_t i = 0; i < _tables.size(); i++)
- {
- Node* cur = _tables[i];
- while (cur)
- {
- Node* next = cur->_next;
- size_t hashi = hs(kot(cur->_data)) % newtables.size();
- 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 make_pair(iterator(newnode,this), false);
- }
- //寻找
- iterator 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 iterator(cur,this);
- cur = cur->_next;
- }
- return end();
- }
- 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;
- }
- else
- {
- prev = cur;
- cur = cur->_next;
- }
- }
- return false;
- }
- private:
- vector<Node*> _tables;//指针数组
- size_t _n;
- };
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
这其中包括只对key进行操作的修改,以及当插入的元素为string型时对其进行的特殊处理。都是我们之前所分享过的知识。下面我们重点来看迭代器。
先来看整体结构:
- template<class K, class T, class KeyOfT, class Hash>
- struct __Iterator
- {
- typedef HashNode<T> Node;
- typedef __Iterator<K, T, KeyOfT, Hash> Self;
- Node* _node;
- HashTable<K, T, KeyOfT, Hash>* _pht;
- __Iterator(Node* node, HashTable<K, T, KeyOfT, Hash>* pht)
- :_node(node)
- ,_pht(pht)
- {}
-
- T& operator*()
- {
- return _node->_data;
- }
- T* operator->()
- {
- return &_node->_data;
- }
- Self& operator++()
- {
- if (_node->_next)
- //当前桶没走完,找到下一个节点
- _node = _node->_next;
- else
- {
- //当前桶走完了,找下一个不为空的桶的第一个节点
- KeyOfT kot;
- Hash hs;
- size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
- i++;
- for (; i < _pht->_tables.size(); i++)
- {
- if (_pht->_tables[i])
- break;
- }
- if (i == _pht->_tables.size())
- //所有桶都走完了,置nullptr
- _node = nullptr;
- else
- _node = _pht->_tables[i];
- }
- return *this;
- }
- bool operator!=(const Self& s)
- {
- return _node != s._node;
- }
- };
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
其中最为重要的莫过于++运算符的重载,因为我们的哈希表是闭散列的哈希桶,所以是以指针数组作为底层。
在执行++操作时,需要先判断当前节点的next是否存在,存在就直接为next节点,不存在就说明当前节点已经是其所属的桶里的最后一个节点,那么接下来的操作就是去寻找下一个不为空的桶的第一个节点。
此时我们需要先计算出当前节点在数组中的位置,然后通过循环判断其后边的位置是否存在桶,如果存在,就返回新桶的第一个节点,不存在,就说明所有的桶都走完了,此时返回空指针nullptr。
- #include"hash.h"
- namespace Myunordered_map
- {
- 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 hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
- V& operator[](const K& key)
- {
- pair<iterator, bool> ret = insert(make_pair(key, V()));
- return ret.first->second;
- }
- pair<iterator, bool> insert(const pair<K, V>& kv)
- {
- return _ht.Insert(kv);
- }
- private:
- hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
- };
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
- #include"hash.h"
- namespace Myunordered_set
- {
- template<class K, class Hash = HashFunc<K>>
- class unordered_set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
- pair<iterator, bool> insert(const K& key)
- {
- return _ht.Insert(key);
- }
- private:
- hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
- };
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
关于unordered_map和set就分享这么多,通过前边的知识的分享和掌握,unordered_map和set的实现也是如鱼得水。
喜欢本篇文章的小伙伴记得一键三连,我们下期再见!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。