最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++11引入的STL中的unordered系列關(guān)聯(lián)式容器

 更新時(shí)間:2025年10月03日 09:32:55   作者:oi嘉菲貓  
STL中的unordered系列容器是C++11引入的基于哈希表實(shí)現(xiàn)的關(guān)聯(lián)式容器,STL unordered系列容器基于哈希表,支持快速查找但遍歷效率低,適用于無序場(chǎng)景;樹形容器基于紅黑樹,有序且性能穩(wěn)定,適用于需要有序的場(chǎng)景

STL中的unordered系列容器是C++11引入的基于哈希表實(shí)現(xiàn)的關(guān)聯(lián)式容器,與傳統(tǒng)的紅黑樹實(shí)現(xiàn)的關(guān)聯(lián)容器(map/set)相比,它們?cè)谠卮鎯?chǔ)和訪問機(jī)制上有顯著差異

1.補(bǔ)充認(rèn)識(shí)

STL中的unordered系列容器的底層就是哈希表,包括unordered_set、unordered_map、unordered_multiset、unordered_multimap四個(gè)。

底層哈希原理

補(bǔ)充:從底層來說應(yīng)該分別類似的命名為tree_map和hash_map,也就是樹形結(jié)構(gòu)和哈希結(jié)構(gòu)的,但是由于map之類的出來的早,后面的為了對(duì)應(yīng)就把hash實(shí)現(xiàn)的命名為unordered_xx。

2.unordered_set

2.1容器原型

C++——16.STL的unordered系列容器_迭代器

  • unordered_set是存儲(chǔ)key鍵值的關(guān)聯(lián)式容器,其允許通過keys快速的索引到與其對(duì)應(yīng)的value。
  • 在unordered_set中,鍵值通常用于惟一地標(biāo)識(shí)元素。
  • 在內(nèi)部,unordered_set沒有對(duì)kye按照任何特定的順序排序, 為了能在常數(shù)范圍內(nèi)找到key,unordered_set將相同哈希值的鍵值放在相同的桶中。
  • unordered_set容器通過key訪問單個(gè)元素要比set快,但它通常在遍歷元素子集的范圍迭代方面效率較低。
  • 它的迭代器至少是前向迭代器。

2.2常用接口

C++——16.STL的unordered系列容器_迭代_02

3.unordered_multiset

和set與multiset的區(qū)別一樣,unordered_multiset相對(duì)于unordered_set支持相同關(guān)鍵碼的存放。

接口區(qū)別:

C++——16.STL的unordered系列容器_迭代器_03

4.unordered_map

4.1容器原型

C++——16.STL的unordered系列容器_迭代_04

  • unordered_map是存儲(chǔ)<key, value>鍵值對(duì)的關(guān)聯(lián)式容器,其允許通過keys快速的索引到與其對(duì)應(yīng)的value。
  • 在unordered_map中,鍵值通常用于惟一地標(biāo)識(shí)元素,而映射值是一個(gè)對(duì)象,其內(nèi)容與此鍵關(guān)聯(lián)。鍵和映射值的類型可能不同。
  • 在內(nèi)部,unordered_map沒有對(duì)<kye, value>按照任何特定的順序排序, 為了能在常數(shù)范圍內(nèi)找到key所對(duì)應(yīng)的value,unordered_map將相同哈希值的鍵值對(duì)放在相同的桶中。
  • unordered_map容器通過key訪問單個(gè)元素要比map快,但它通常在遍歷元素子集的范圍迭代方面效率較低。
  • unordered_maps實(shí)現(xiàn)了直接訪問操作符(operator[]),它允許使用key作為參數(shù)直接訪問value
  • 它的迭代器至少是前向迭代器。

4.2常用接口

與unordered_set相比,unordered_map就是鍵值對(duì)KV模型,并且提供了[]重載和at接口,這兩個(gè)與map相似功能。

其他接口功能與unordered_set相同。

5.unordered_multimap

unordered_multimap和unordered_map的區(qū)別就是unordered_multiset和unordered_multiset的區(qū)別。

另外就是unordered_multimap不支持[]和at。

6.樹形關(guān)聯(lián)容器和哈希關(guān)聯(lián)容器的對(duì)比

特性

哈希容器

樹形容器

底層結(jié)構(gòu)

哈希表(順序表+順序表/紅黑表)

紅黑樹(平衡二叉搜索樹)

元素順序

無序

有序

平均時(shí)間復(fù)雜度

O(1)

O(log_2 N)

最壞時(shí)間復(fù)雜度

O(N)(所有元素都沖突,實(shí)際幾乎不可能)

O(log_2 N)

迭代器

單向迭代器

雙向迭代器

關(guān)鍵特性

增刪查改都很快,遍歷較慢。性能依賴哈希函數(shù)。

插入后自然有序。

適用場(chǎng)景

快速查找,不關(guān)注順序。

需要元素有序。

小總結(jié):除非有有序的要求,不然都可以先考慮哈希容器。

7.unordered系列模擬實(shí)現(xiàn)

7.1重要補(bǔ)充

1)具體存放什么數(shù)據(jù)類型應(yīng)該是set和map層面決定的,底層的哈希表只是存放數(shù)據(jù),所以需要一個(gè)從存放數(shù)據(jù)提取關(guān)鍵碼的KeyOfT反函數(shù)。

2)另外還需要一個(gè)哈希函數(shù)來處理不能直接取模的情況。

3)哈希表的迭代器迭代邏輯:單鏈表迭代+順序表的哈希桶迭代。

4)如果使用自定義類型取作為樹形關(guān)聯(lián)容器的關(guān)鍵碼的話,需要提供一個(gè)小于比較仿函數(shù),有了小于也就有了大于和等于。

5)如果使用自定義類型取作為哈希關(guān)聯(lián)容器的關(guān)鍵碼的話,需要提供一個(gè)等于比較仿函數(shù)。

6)set的迭代器無論是普通迭代器還是const迭代器在底層都是使用const迭代器。

7.2代碼

源碼

7.2.1哈希表

#pragma once 
#include <iostream>
// 使用哈希桶解決哈希表的哈希沖突
#include <vector>
#include <utility>

using namespace std;

namespace lbq
{
    // 將輸入轉(zhuǎn)成整型的哈希函數(shù)
    template<class K>
    struct HashFunc 
    {
        size_t operator()(const K& key)
        {
            return (size_t)key;
        }
    };
    
    // 針對(duì)常用的字符串類型的特化
    template<>
    struct HashFunc<string>
    {
        size_t operator()(const string& str)
        {
            size_t ret = 0;
            for(auto& ele : str)
            {
                ret = ret * 131 + ele;
            }
    
            return ret;
        }
    };

    // 哈希桶具體存儲(chǔ)的數(shù)據(jù)類型
    // 實(shí)際為一個(gè)單鏈表節(jié)點(diǎn)
    template<class T>
    struct _HashNode
    {
        T _data;
        _HashNode<T>* _next;

        _HashNode(const T& data)
            : _data(data)
            , _next(nullptr)
        {}
    };

    // 哈希表的迭代器,其實(shí)是順序表迭代+鏈表迭代
    template<class K, class T, class KeyOfT, class Hash > class HashTable;   // 迭代器中需要訪問,提前聲明
    template<class K, class T, class KeyOfT, class Hash>
    struct _HashTableIterator
    {
        typedef _HashNode<T> Node;
        typedef HashTable<K, T, KeyOfT, Hash> HT;
        typedef _HashTableIterator<K, T, KeyOfT, Hash> Iterator;

        Node* _node;
        HT* _ht;

        _HashTableIterator(Node* node, HT* ht)
            : _node(node)
            , _ht(ht)
        {}

        bool operator==(const Iterator& it)const 
        {
            return _node == it._node;
        }

        bool operator!=(const Iterator& it)const 
        {
            return _node != it._node;
        }

        T& operator*()
        {
            return _node->_data;
        }

        T* operator->()
        {
            return &(_node->_data);
        }

        Iterator operator++()
        {
            if(_node->_next != nullptr)
            {
                _node = _node->_next;
            }
            else 
            {
                // 找下一個(gè)桶的位置
                size_t table_index = Hash()(KeyOfT()(_node->_data)) % _ht->_table.size();
                while(++table_index < _ht->_table.size())
                {
                    if(_ht->_table[table_index] != nullptr)
                    {
                        _node = _ht->_table[table_index];
                        break;
                    }
                }

                // 如果后面已經(jīng)沒有桶了
                if(table_index == _ht->_table.size())
                {
                    _node = nullptr;
                }
            }

            return *this;
        }

        Iterator operator++(int)
        {
            Iterator tmp(_node, _ht);
            operator++();
            return tmp;
        }
    };

    // 使用除留余數(shù)法作為哈希表的哈希函數(shù),使用哈希桶解決沖突
    // K:關(guān)鍵碼數(shù)據(jù)類型
    // T:存儲(chǔ)的數(shù)據(jù)類型,Key或者pair<K, V>
    // KeyOfT:從存儲(chǔ)的數(shù)據(jù)中提取關(guān)鍵碼
    // Hash:將關(guān)鍵碼轉(zhuǎn)成整型用于取模運(yùn)算
    template<class K, class T, class KeyOfT, class Hash>
    class HashTable
    {
    private:
        typedef _HashNode<T> Node;
        friend struct _HashTableIterator<K, T, KeyOfT, Hash>;

    public:
        typedef _HashTableIterator<K, T, KeyOfT, Hash> iterator;

        iterator begin()
        {
            for(size_t i = 0; i < _table.size(); i++)
            {
                if(_table[i] != nullptr)
                {
                    return iterator(_table[i], this);
                }
            }

            return end();
        }

        iterator end()
        {
            return iterator(nullptr, this);
        }

        //HashTable()
        //{
        //    _table.resize(10, nullptr);
        //    _sz = 0;
        //}

        ~HashTable()
        {
            for(size_t i = 0; i < _table.size(); i++)
            {
                Node* cur = _table[i];
                while(cur != nullptr)
                {
                    Node* next = cur->_next;
                    delete cur;
                    cur = next;
                }
                _table[i] = nullptr;
            }
        }

        pair<iterator, bool> insert(const T& data)
        {
            Hash hash;
            KeyOfT kot;
            iterator find_it = find(kot(data));
            if(find_it != end())
            {
                // 已經(jīng)存在相同的元素
                return make_pair(find_it, false);
            }
            
            if(_table.size() == 0 || _sz == _table.size())
            {
                // 順序表為空,或者載荷因子大于1時(shí)增容
                size_t new_size = _table.size() == 0 "h14">7.2.2unordered_set
#pragma once 
// hash set模擬實(shí)現(xiàn)
#include "hashtable.hpp"

namespace lbq
{
    template<class K, class Hasher = HashFunc<K>>
    class unordered_set 
    {
    private:
        struct SetKeyOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };

        typedef HashTable<K, K, SetKeyOfT, Hasher> HT;

    public:
        typedef typename HT::iterator iterator;

        iterator begin()
        {
            return _ht.begin();
        }

        iterator end()
        {
            return _ht.end();
        }

        bool empty()
        {
            return _ht.empty();
        }

        size_t size()
        {
            return _ht.size();
        }

        iterator find(const K& key)
        {
            return _ht.find(key);
        }

        size_t count(const K& key)
        {
            return _ht.count(key);
        }

        pair<iterator, bool> insert(const K& key)
        {
            return _ht.insert(key);
        }

        bool erase(const K& key)
        {
            return _ht.erase(key);
        }

        size_t bucket_count()
        {
            return _ht.bucket_count();
        }

        size_t bucket_size(size_t n)
        {
            return _ht.bucket_size(n);
        }


    private:
        HT _ht;
    };
}

7.2.3unordered_map

#pragma once 
// unorder_map 模擬實(shí)現(xiàn)
#include "hashtable.hpp"

namespace lbq
{
    template<class K, class V, class Hasher = HashFunc<K>>
    class unordered_map 
    {
    private:
        typedef pair<K, V> T;
        struct MapKeyOfT
        {
            const K& operator()(const T& kv)
            {
                return kv.first;
            }
        };
        typedef HashTable<K, T, MapKeyOfT, Hasher> HT;

    public:
        typedef typename HT::iterator iterator;

        iterator begin()
        {
            return _ht.begin();
        }

        iterator end()
        {
            return _ht.end();
        }

        size_t size()
        {
            return _ht.size();
        }

        bool empty()
        {
            return _ht.empty();
        }

        V& operator[](const K& key)
        {
            pair<iterator, bool> ret = _ht.insert(make_pair(key, V()));
            return ret.first->second;
        }

        iterator find(const K& key)
        {
            return _ht.find(key);
        }

        size_t count(const K& key)
        {
            return _ht.count(key);
        }

        pair<iterator, bool> insert(const T& kv)
        {
            return _ht.insert(kv);
        }

        bool erase(const K& key)
        {
            return _ht.erase(key);
        }

        size_t bucket_count()
        {
            return _ht.bucket_count();
        }

        size_t bucket_size(const size_t& n )
        {
            return _ht.bucket_size(n);
        }

    private:
        HT _ht;
    };
}

到此這篇關(guān)于C++11引入的STL中的unordered系列關(guān)聯(lián)式容器的文章就介紹到這了,更多相關(guān)C++的STL中的unordered容器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實(shí)現(xiàn)學(xué)籍管理系統(tǒng)

    C語言實(shí)現(xiàn)學(xué)籍管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • VC中SendMessage和PostMessage的區(qū)別

    VC中SendMessage和PostMessage的區(qū)別

    這篇文章主要介紹了VC中SendMessage和PostMessage的區(qū)別,較為全面的分析了SendMessage和PostMessage運(yùn)行原理及用法上的不同之處,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • C語言實(shí)現(xiàn)模擬USB對(duì)8bit數(shù)據(jù)的NRZI編碼輸出

    C語言實(shí)現(xiàn)模擬USB對(duì)8bit數(shù)據(jù)的NRZI編碼輸出

    今天小編就為大家分享一篇關(guān)于C語言實(shí)現(xiàn)模擬USB對(duì)8bit數(shù)據(jù)的NRZI編碼輸出,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C++探索構(gòu)造函數(shù)私有化會(huì)產(chǎn)生什么結(jié)果

    C++探索構(gòu)造函數(shù)私有化會(huì)產(chǎn)生什么結(jié)果

    C++的構(gòu)造函數(shù)的作?:初始化類對(duì)象的數(shù)據(jù)成員。即類的對(duì)象被創(chuàng)建的時(shí)候,編譯系統(tǒng)對(duì)該對(duì)象分配內(nèi)存空間,并?動(dòng)調(diào)?構(gòu)造函數(shù),完成類成員的初始化。構(gòu)造函數(shù)的特點(diǎn):以類名作為函數(shù)名,?返回類型
    2022-05-05
  • Qt中QCommandLinkButton控件的使用

    Qt中QCommandLinkButton控件的使用

    QCommandLinkButton 是 Qt 框架中 QtWidgets 模塊的一個(gè)類,它提供了一個(gè)結(jié)合了文本標(biāo)簽和按鈕功能的控件,本文主要介紹了Qt中QCommandLinkButton控件的使用,感興趣的可以了解一下
    2025-04-04
  • C語言單鏈表實(shí)現(xiàn)方法詳解

    C語言單鏈表實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了C語言單鏈表實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了基于C語言的單鏈表定義、創(chuàng)建、添加、刪除、排序、打印等操作技巧,并附帶了相關(guān)的優(yōu)化算法,需要的朋友可以參考下
    2018-04-04
  • C++的程序流程結(jié)構(gòu)你了解多少

    C++的程序流程結(jié)構(gòu)你了解多少

    這篇文章主要為大家詳細(xì)介紹了C++的程序流程結(jié)構(gòu),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Linux下實(shí)現(xiàn)C++操作Mysql數(shù)據(jù)庫

    Linux下實(shí)現(xiàn)C++操作Mysql數(shù)據(jù)庫

    由于工作需要抽出一周的時(shí)間來研究C/C++訪問各種數(shù)據(jù)庫的方法,并打算封裝一套數(shù)據(jù)庫操作類,現(xiàn)在奉上最簡單的一部分:在Linux下訪問MySQL數(shù)據(jù)庫。
    2017-05-05
  • C++ 內(nèi)聯(lián)函數(shù)inline案例詳解

    C++ 內(nèi)聯(lián)函數(shù)inline案例詳解

    這篇文章主要介紹了C++ 內(nèi)聯(lián)函數(shù)inline案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • C++string中的insert()插入函數(shù)詳解

    C++string中的insert()插入函數(shù)詳解

    這篇文章主要介紹了C++string中的insert()插入函數(shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論

新宾| 上犹县| 斗六市| 克东县| 策勒县| 婺源县| 淳化县| 吴桥县| 崇礼县| 滦南县| 江津市| 奈曼旗| 双江| 平遥县| 虎林市| 静乐县| 安新县| 察雅县| 宜阳县| 化隆| 邹平县| 固始县| 成都市| 托克托县| 日喀则市| 乐安县| 武清区| 五常市| 开阳县| 南木林县| 始兴县| 松江区| 蚌埠市| 津市市| 会东县| 滕州市| 富川| 新巴尔虎右旗| 剑阁县| 金平| 晴隆县|