模拟实现unordered_mapunordered_set
模擬實現unordered_map&unordered_set
文章目錄
- 模擬實現unordered_map&unordered_set
- 1. std::unordered_map 的定義與特性
- 2. 構造 std::unordered_map:
- 3. 賦值操作
- 4. 迭代器操作
- 5. 容量操作
- 6. 訪問操作
- 7. 插入操作
- 8. 刪除操作
- 9. 查找操作
- 10. 桶操作
- 11. 模擬實現unordered_map
- 12. 模擬實現unordered_set
1. std::unordered_map 的定義與特性
所在頭文件:<unordered_map>
std::unorederd_map 類模板:
template < class Key, // unordered_map::key_typeclass T, // unordered_map::mapped_typeclass Hash = hash<Key>, // unordered_map::hasherclass Pred = equal_to<Key>, // unordered_map::key_equalclass Alloc = allocator< pair<const Key,T> > // unordered_map::allocator_type> class unordered_map;1. unordered_map是存儲<key, value>鍵值對的關聯式容器,其允許通過keys快速的索引到與其對應的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. 它的迭代器至少是前向迭代器
7. 關聯性:std::unorederd_map 是一個關聯容器,其中的元素根據鍵來引用,而不是根據索引來引用。
8. 無序性:在內部,std::unordered_map中的元素不會根據其鍵值或映射值按任何特定順序排序,而是根據其哈希值組織到桶中,以允許通過鍵值直接快速訪問各個元素(常量的平均時間復雜度)。
9. 唯一性:std::unorederd_map中的元素的鍵是唯一的。
一些類型定義:
類型成員 定義 key_type 第一個模板參數(Key) mapped_type 第二個模板參數(T) value_type pair<const key_type,mapped_type> hasher 第三個模板參數(Hash) key_equal 第四個模板參數(Pred)2. 構造 std::unordered_map:
3. 賦值操作
| 復制 | unordered_map& operator= ( const unordered_map& ump ); |
| 移動 | unordered_map& operator= ( unordered_map&& ump ); |
| 初始化列表 | unordered_map& operator= ( intitializer_list<value_type> il ); |
4. 迭代器操作
4.1 指向整個容器中的元素
| iterator begin() noexcept;const_iterator begin() const noexcept; | 返回一個迭代器,指向第一個元素 |
| iterator end() noexcept;const_iterator end() const noexcept; | 返回一個迭代器,指向尾后元素 |
| const_iterator cbegin() const noexcept; | 返回一個常量迭代器,指向第一個元素 |
| const_iterator cend() const noexcept; | 返回一個常量迭代器,指向尾后元素 |
4.2 指向某個桶中的元素
| local_iterator begin( size_type n );const_local_iterator begin ( size_type n ) const; | 返回一個迭代器,指向第n個桶內的第一個元素 |
| local_iterator end(size_type n);const_local_iterator end (size_type n) const; | 返回一個迭代器,指向第n個桶內的尾后元素 |
| const_local_iterator cbegin( size_type n ) const; | 返回一個常量迭代器,指向第n個桶內的第一個元素 |
| const_local_iterator cend( size_type n ) const | 返回一個常量迭代器,指向第n個桶內的尾后元素 |
5. 容量操作
| bool empty() const noexcept; | unordered_map 是否為空 |
| size_type size() const noexcept; | 獲取unordered_map 中元素的數量 |
6. 訪問操作
| 使用方括號([]) | mapped_type& operator[] (const key_type& k);mapped_type& operator[] (key_type&& k); | 如果 k 匹配容器中某個元素的鍵,則該函數返回該映射值的引用。如果 k 與容器中任何元素的鍵都不匹配,則該函數將使用該鍵插入一個新元素,并返回該映射值的引用。 |
| 使用 at() mapped_type& at (const key_type& k); | const mapped_type& at (const key_type& k) const; | 如果 k 匹配容器中某個元素的鍵,則該函數返回該映射值的引用。如果 k 與容器中任何元素的鍵都不匹配,則該函數將拋出 out_of_range 異常。 |
注意:const std::unordered_map 不能使用 operator[] 操作!!
7. 插入操作
8. 刪除操作
9. 查找操作
10. 桶操作
unordered_set的接口基本和unordered_map的接口一致,其沒有operator[]操作
11. 模擬實現unordered_map
因為unordered_map的底層是使用的哈希表的結構,所以必須有一個哈希表
哈希原理
如果要按照前文當中的哈希表模擬實現unordered_map就需要進行改造。
11.1 哈希表的改造:
HashTable.hpp
#pragma once #include<vector> #include"Common.hpp"template<class T> struct HashNode {HashNode(const T& data = T()):_pNext(nullptr),_data(data){}HashNode<T>* _pNext;T _data; };template<class T, class KorV, class DF = DFStr> class HashBucket;template<class T, class KorV,class DF = DFStr> struct Iterator {typedef HashNode<T> Node;typedef Iterator<T, KorV, DF> Self;Iterator(Node* pNode = nullptr, HashBucket<T, KorV, DF>* ht = nullptr):_pNode(pNode),_ht(ht){}T& operator*() {return _pNode->_data;}T* operator->() {return &(_pNode->_data);}Self& operator++() {Next();return *this;}Self operator++(int) {Self tmp(_pNode);Next();return tmp;}bool operator==(Self& t) {return _pNode == t._pNode;}bool operator!=(Self& t) {return _pNode != t._pNode;}void Next() {if (_pNode->_pNext) {_pNode = _pNode->_pNext;}else {size_t addr = _ht->HashFunc(_pNode->_data);for (int i = addr + 1; i < _ht->_arr.size(); ++i) {if (_ht->_arr[i]) {_pNode = _ht->_arr[i];return;}}_pNode = nullptr;}}Node* _pNode;HashBucket<T, KorV, DF>* _ht; };template<class T, class KorV, class DF> class HashBucket { public:typedef HashNode<T> Node;typedef HashBucket<T, KorV, DF> Self;typedef Iterator<T, KorV, DF> iterator;friend struct Iterator<T, KorV, DF>; public:HashBucket(size_t size = 11):_size(0){_arr.resize(size);}~HashBucket() {Clear();}std::pair<iterator, bool> Insert(const T& data) {CheckCapacity();size_t addr = HashFunc(data);//查找是否有重復節點Node* ptr = _arr[addr];while (ptr) {if (KorV()(ptr->_data) == KorV()(data)) return make_pair(iterator(ptr, this), false);ptr = ptr->_pNext;}ptr = new Node(data);ptr->_pNext = _arr[addr];_arr[addr] = ptr;++_size;return make_pair(iterator(ptr, this), true);}size_t Erase(const T& data) {size_t addr = HashFunc(data);Node* ptr = _arr[addr];Node* pre = nullptr;while (ptr) {if (ptr->_data == data) {if (!pre) //刪除頭結點_arr[addr] = ptr->_pNext;else //刪除中間節點pre->_pNext = ptr->_pNext;delete ptr;--_size;return 1;}else {pre = ptr;ptr = ptr->_pNext;}}return 0;}iterator find(const T& data) const{size_t addr = HashFunc(data);Node* ptr = _arr[addr];while (ptr) {if (KorV()(ptr->_data) == KorV()(data))return iterator(ptr, this);ptr = ptr->_pNext;}return iterator(nullptr, this);}size_t size() const{return _size;}bool empty()const {return _size == 0;}iterator begin() {for (int i = 0; i < _arr.size(); ++i) {if (_arr[i]) {return iterator(_arr[i], this);}}return iterator(nullptr, this);}iterator end() {return iterator(nullptr, this);}void Clear() {for (size_t i = 0; i < _arr.size(); ++i) {Node* ptr = _arr[i];while (ptr) {_arr[i] = ptr->_pNext;delete ptr;ptr = _arr[i];}}_size = 0;}size_t bucket_count() const{return _arr.size();}size_t bucket_size(size_t n) const{if (n >= _arr.size())return 0;size_t count = 0;Node* ptr = _arr[n];while (ptr) {++count;ptr = ptr->_pNext;}return count;}size_t bucket(const T& data) {return HashFunc(data);}void Swap(Self& t) {_arr.swap(t._arr);std::swap(_size, t._size);} private:void CheckCapacity() { //擴容if (_size == _arr.size()) {size_t newSize = GetNextPrime(_arr.size());Self newBucket(newSize);for (size_t i = 0; i < _arr.size(); ++i) {Node* ptr = _arr[i];while (ptr) {size_t addr = newBucket.HashFunc(ptr->_data);_arr[i] = ptr->_pNext;ptr->_pNext = newBucket._arr[addr];newBucket._arr[addr] = ptr;++newBucket._size;ptr = _arr[i];}}Swap(newBucket);}}size_t HashFunc(const T data) const{return DF()(KorV()(data)) % _arr.size();} private:std::vector<Node*> _arr;size_t _size; };unordered_map
#pragma once #include"HashBucket.hpp"template<class K,class V> class Unordered_map {typedef std::pair<K, V> ValueType;typename typedef HashBucket<ValueType, KORV>::iterator iterator;struct KORV {const K& operator()(const ValueType& data)const {return data.first;}}; public:Unordered_map(size_t size = 11):_ht(size){}iterator begin(){return _ht.begin();}iterator end(){return _ht.end();}bool empty()const {return _ht.empty();}size_t size()const {return _ht.size();}std::pair<iterator,bool> insert(const ValueType& data){return _ht.Insert(data);}size_t erase(const K& key){return _ht.Erase(ValueType(key,V()));}iterator find(const K& key) const{return _ht.find(ValueType(key, V()));}void clear() {_ht.Clear();}void swap(const Unordered_map<K,V>& m) {_ht.Swap(m._ht);}V& operator[](const K& k) {return (*(insert(ValueType(k, V())).first)).second;}size_t buck_count()const {return _ht.bucket_count();}size_t buck_size(size_t n)const {return _ht.bucket_size(n);}size_t bucket(const K& k) {return _ht.bucket(ValueType(k, V()));} private:HashBucket<ValueType, KORV> _ht; };12. 模擬實現unordered_set
#pragma once #include"HashBucket.hpp"template<class K> class Unordered_set {typedef K ValueType;typename typedef HashBucket<ValueType, KORV>::iterator iterator;struct KORV{const ValueType& operator()(const ValueType& data)const {return data;}}; public:Unordered_set(size_t size = 11):_ht(size){}iterator begin() {return _ht.begin();}iterator end() {return _ht.end();}bool empty()const {return _ht.empty();}size_t size()const {return _ht.size();}std::pair<iterator, bool> insert(const ValueType& data) {return _ht.Insert(data);}size_t erase(const ValueType& key) {return _ht.Erase(key);}iterator find(const ValueType& key) const {return _ht.find(key);}void clear() {_ht.Clear();}void swap(const Unordered_set<K>& m) {_ht.Swap(m._ht);}size_t buck_count()const {return _ht.bucket_count();}size_t buck_size(size_t n)const {return _ht.bucket_size(n);}size_t bucket(const ValueType& k) {return _ht.bucket(k);} private:HashBucket<ValueType, KORV> _ht; };總結
以上是生活随笔為你收集整理的模拟实现unordered_mapunordered_set的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MYSQL视图用户管理
- 下一篇: 模拟实现mapset