1. unordered系列关联式容器
在C++98 中, STL 提供了底层为红黑树布局的一系列关联式容器,在查询时效率可到达 ,即最差情况下必要比力红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好的查询是,进行很少的比力次数就可以或许将元素找到,因此在C++11 中, STL 又提供了 4 个unordered系列的关联式容器,这四个容器与红黑树布局的关联式容器利用方式根本雷同,只是其底层布局差别,该系列容器利用哈希表进行封装。 2. unordered_map的先容
1. unordered_map 是存储 <key, value> 键值对的关联式容器,其允许通过 key 快速的索引到与其对应的value 。 2. 在 unordered_map 中,键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能差别。 3. 在内部 ,unordered_map 没有对 <kye, value> 按照任何特定的顺序排序 , 为了能在常数范围内找到key 所对应的 value , unordered_map 将雷同哈希值的键值对放在雷同的桶中。 4. unordered_map 容器通过 key 访问单个元素要比 map 快,但它通常在遍历元素子集的范围迭代方面效率较低。 5. unordered_maps 实现了直接访问利用符 (operator[ ]) ,它允许利用 key 作为参数直接访问value。 6. 它的迭代器至少是前向迭代器。 3. unordered_map的利用
1. unordered_map的构造
函数声明 | 功能先容 | unordered_map() | 构造差别格式的 unordered_map 对象 | 2. unordered_map的容量
函数声明 | 功能先容 | bool empty() const | 检测 unordered_map 是否为空 | size_t size() const | 获取 unordered_map 的有效元素个数 | 3. unordered_map的迭代器
函数声明 | 功能先容 | iterator begin() | 返回 unordered_map 第一个元素的迭代器 | iterator end() | 返回 unordered_map 末了一个元素下一个位置的迭代器 | const_iterator cbegin() const | 返回 unordered_map 第一个元素的 const 迭代器 | const_iterator cend() const | 返回 unordered_map 末了一个元素下一个位置的 const 迭代器 |
4. unordered_map的元素访问
函数声明 | 功能先容 | mapped_type& operator[ ] (const key_type& k) | 返回与 key 对应的 value ,没有返回一个默认值 | 注意:该函数中现实调用哈希桶的插入利用,用参数 key 与 V() 构造一个默认值往底层哈希桶中插入,如果key 不在哈希桶中,插入乐成,返回 V() ,插入失败,说明 key 已经在哈希桶中,将key 对应的 value 返回。 5. unordered_map的查询
函数声明 | 功能先容 | iterator find(const K& key) | 返回 key 在哈希桶中的位置 | size_t count(const K& key) | 返回哈希桶中关键码为 key 的键值对的个数 | 注意: unordered_map 中 key 是不能重复的,因此 count 函数的返回值最大为 1 6. unordered_map的修改利用
函数声明 | 功能先容 | pair<iterator,bool> insert (const value_type& x ) | 向容器中插入键值对 | size_type erase ( const key_type& x )
| 删除容器中的键值对 | void clear() | 清空容器中有效元素个数 | void swap(unordered_map&) | 交换两个容器中的元 | 7. unordered_map的桶利用
函数声明 | 功能先容 | size_t bucket_count()const | 返回哈希桶中桶的总个数 | size_t bucket_size(size_t n)const | 返回 n 号桶中有效元素的总个数 | size_t bucket(const K& key) | 返回元素 key 地点的桶号 |
4.unordered_map的模拟实现
首先我们要利用哈希表进行封装unordered_map即可,如下是HashTable.cpp的文件,有关哈希表的详细先容,可以点击了解C++哈希表。
- #include <iostream>
- #include <vector>
- using namespace std;
- namespace OpenHash
- {
- template<class T>
- struct HashNode
- {
- T _data;
- HashNode* _next;
- HashNode(const T& data)
- :_data(data)
- , _next(nullptr)
- {}
- };
- //将key转换为整型方便取模
- template <class K>
- struct Hash
- {
- size_t operator()(const K& key)
- {
- return key;
- }
- };
- //模板特化,将string类型转换为整型
- template<>
- class Hash<string>
- {
- size_t operator()(const string& s)
- {
- size_t ret = 0;
- for (auto e : s)
- {
- ret = ret * 31 + e;
- }
- return ret;
- }
- };
- //实现迭代器
- //因为迭代器的实现需要借助HashTable,所以需要前置定义
- template <class K, class T, class KeyOfT, class HashFunc = Hash<K>>
- class HashTable;
- template <class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc = Hash<K>>
- struct HashTableIterator
- {
- typedef typename HashNode<T> Node;
- typedef typename HashTableIterator<K, T, Ptr, Ref, KeyOfT, HashFunc> Self;
- typedef typename HashTable<K, T, KeyOfT, HashFunc> HashTable;
- HashTable* _ht;
- Node* _node;
- HashTableIterator() = default;
- HashTableIterator(const Node*& node, const HashTable*& ht)
- :_ht(ht)
- , _node(node)
- {}
- Self& operator++()
- {
- //遍历当前桶
- if (_node->_next)
- _node = _node->_next;
- //找下一个桶
- else
- {
- KeyOfT kot;
- HashFunc hf;
- //获取索引值
- size_t index = hf(kot(_node->_data)) % _ht->_table.size();
- ++index;
- while (index < _ht->_table.size() && _ht->_table[index] == nullptr)
- ++index;
- if (index == _ht->_table.size())
- _node = nullptr;
- else
- _node = _ht->_table[index];
- }
- return *this;
- }
- Ref operator*()
- {
- return _node->_data;
- }
- Ptr operator->()
- {
- return &_node->_data;
- }
- bool operator==(const Self& s)
- {
- return _node == s._node;
- }
- bool operator!=(const Self& s)
- {
- return _node != s._node;
- }
- };
- template <class K, class T, class KeyOfT, class HashFunc>
- class HashTable
- {
- public:
- //友元(因为iterator需要用到_table)
- template <class K, class T, class Ptr, class Ref, class KeyOfT, class HashFunc>
- friend struct HashTableIterator;
- typedef typename HashNode<T> Node;
- typedef typename HashTableIterator<K, T, T*, T&, KeyOfT, HashFunc> iterator;
- //构造函数
- HashTable()
- :_table(vector<Node*>())
- , _n(0)
- {}
- iterator begin()
- {
- for (size_t i = 0; i < _table.size(); i++)
- {
- if (_table[i])
- return iterator(_table[i], this);
- }
- return iterator(nullptr, this);
- }
- iterator end()
- {
- return iterator(nullptr, this);
- }
- iterator find(const K& key)
- {
- if (_table.size() == 0)
- {
- return iterator(nullptr, this);
- }
- KeyOfT kot;
- HashFunc hf;
- size_t index = hf(key) % _table.size();
- Node* cur = _table[index];
- while (cur)
- {
- if (kot(cur->_data) == key)
- return iterator(cur, this);
- cur = cur->_next;
- }
- return iterator(nullptr, this);
- }
- pair<iterator, bool> insert(const K& key)
- {
- //第一次插入需要扩容
- if (_table.size() == 0)
- _table.resize(10);
- //不能出现重复数据
- if (find(key) != iterator(nullptr, this))
- {
- return make_pair(find(key), false);
- }
- KeyOfT kot;
- HashFunc hf;
- //桶的个数是一定的,随着元素的不断插入,每个桶中元素的个数不断增多,极端情况下,
- //可能会导致一个桶中链表节点非常多,会影响的哈希表的性能,因此在一定条件下需要对
- //哈希表进行增容,那该条件怎么确认呢?开散列最好的情况是:每个哈希桶中刚好挂一个
- //节点,再继续插入元素时,每一次都会发生哈希冲突,因此,在元素个数刚好等于桶的个数
- //时,可以给哈希表增容。
- //负载因子到1,需要扩容
- if (_n == _table.size())
- {
- vector<Node*> newtable;
- newtable.resize(_table.size() * 2);
- //重新映射到新表
- for (auto e : _table)
- {
- Node* cur = e;
- while (cur)
- {
- size_t index = hf(kot(cur->_data)) % newtable.size();
- cur->_next = newtable[index];
- newtable[index] = cur;
- cur = cur->_next;
- }
- }
- }
- size_t index = hf(key) % _table.size();
- Node*& cur = _table[index];
- while (cur)
- cur = cur->_next;
- cur = new Node(key);
- return make_pair(iterator(cur, this), true);
- }
- bool erase(const K& key)
- {
- KeyOfT kot;
- HashFunc hf;
- size_t index = hf(key) % _table.size();
- Node* cur = _table[index], * pre = _table[index];
- while (cur)
- {
- if (kot(cur->_data) == key)
- {
- //要删除该位置第一个元素
- if (cur == pre)
- _table[index] = cur->_next;
- else
- pre->_next = cur->_next;
- delete cur;
- _n--;
- return true;
- }
- pre = cur;
- cur = cur->_next;
- }
- return false;
- }
- private:
- vector<Node*> _table;
- size_t _n;//有效数据个数
- };
- }
复制代码 unordered_map.cpp文件如下
- #include"HashTable.cpp"
- namespace lbk
- {
- template<class K,class Hash=OpenHash::Hash<K>>
- class unordered_set
- {
- struct SetKeyOfT
- {
- const K& operator()(const K& key)
- {
- return key;
- }
- };
- public:
- typedef typename OpenHash::HashTable<K,K,SetKeyOfT,Hash>::iterator iterator;
- iterator begin()
- {
- return _ht.begin();
- }
- iterator end()
- {
- return _ht.end();
- }
- iterator find(const K& key)
- {
- return _ht.find(key);
- }
- pair<iterator, bool> insert(const K& key)
- {
- return _ht.insert(key);
- }
- bool erase(const K& key)
- {
- return _ht.erase(key);
- }
- private:
- OpenHash::HashTable<K, K, SetKeyOfT, Hash> _ht;
- };
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |