日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

模拟实现unordered_mapunordered_set

發布時間:2024/4/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 模拟实现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 哈希表的改造:

  • 模板參數列表的改造
  • // K:關鍵碼類型 // V: 不同容器V的類型不同,如果是unordered_map,V代表一個鍵值對,如果是 //unordered_set,V為 K // KeyOfValue: 因為V的類型不同,通過value取key的方式就不同,詳細見 //unordered_map/set的實現 // HF: 哈希函數仿函數對象類型,哈希函數使用除留余數法,需要將Key轉換為整形數字才能取模 template<class K, class V, class KeyOfValue, class HF = DefHashF<T> > class HashBucket;
  • 增加迭代器操作:
  • // 為了實現簡單,在哈希桶的迭代器類中需要用到hashBucket本身, template<class K, class V, class KeyOfValue, class HF> class HashBucket; // 注意:因為哈希桶在底層是單鏈表結構,所以哈希桶的迭代器不需要--操作 template <class K, class V, class KeyOfValue, class HF> struct HBIterator {typedef HashBucket<K, V, KeyOfValue, HF> HashBucket;typedef HashBucketNode<V>* PNode;typedef HBIterator<K, V, KeyOfValue, HF> Self;HBIterator(PNode pNode = nullptr, HashBucket* pHt = nullptr);Self& operator++(){// 當前迭代器所指節點后還有節點時直接取其下一個節點if (_pNode->_pNext)_pNode = _pNode->_pNext;else{// 找下一個不空的桶,返回該桶中第一個節點size_t bucketNo = _pHt->HashFunc(KeyOfValue()(_pNode->_data))+1;for (; bucketNo < _pHt->BucketCount(); ++bucketNo){if (_pNode = _pHt->_ht[bucketNo])break;}}return *this;}Self operator++(int);V& operator*();V* operator->();bool operator==(const Self& it) const;bool operator!=(const Self& it) const;PNode _pNode; // 當前迭代器關聯的節點HashBucket* _pHt; // 哈希桶--主要是為了找下一個空桶時候方便 };
  • 增加通過key獲取value操作:
  • template<class K, class V, class KeyOfValue, class HF = DefHashF<T> > class HashBucket {friend HBIterator<K, V, KeyOfValue, HF>;// ...... public:typedef HBIterator<K, V, KeyOfValue, HF> Iterator;//// ...// 迭代器Iterator Begin(){size_t bucketNo = 0;for (; bucketNo < _ht.capacity(); ++bucketNo){if (_ht[bucketNo])break;}if (bucketNo < _ht.capacity())return Iterator(_ht[bucketNo], this);elsereturn Iterator(nullptr, this);}Iterator End(){ return Iterator(nullptr, this);}Iterator Find(const K& key);Iterator Insert(const V& data);Iterator Erase(const K& key);// 為key的元素在桶中的個數size_t Count(const K& key){if(Find(key) != End())return 1;return 0;}size_t BucketCount()const{ return _ht.capacity();}size_t BucketSize(size_t bucketNo){size_t count = 0;PNode pCur = _ht[bucketNo];while(pCur){count++;pCur = pCur->_pNext;}return count;}// ...... };

    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的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。