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

C++ set和multiset的使用小結(jié)

 更新時(shí)間:2025年12月15日 08:35:21   作者:Fcy648  
本文介紹了C++中序列式容器和關(guān)聯(lián)式容器的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1. 序列式容器和關(guān)聯(lián)式容器(了解)

前面我們已經(jīng)接觸過(guò)STL中的部分容器如:string、vector、list、deque、array、forward_list等,這些容器統(tǒng)稱(chēng)為序列式容器,因?yàn)檫壿嫿Y(jié)構(gòu)為線性序列的數(shù)據(jù)結(jié)構(gòu),兩個(gè)位置存儲(chǔ)的值之間一般沒(méi)有緊密的關(guān)聯(lián)關(guān)系,比如交換一下,他依舊是序列式容器。順序容器中的元素是按他們?cè)谌萜髦械拇鎯?chǔ)位置來(lái)順序保存和訪問(wèn)的。

關(guān)聯(lián)式容器也是用來(lái)存儲(chǔ)數(shù)據(jù)的,與序列式容器不同的是,關(guān)聯(lián)式容器邏輯結(jié)構(gòu)通常是非線性結(jié)構(gòu),兩個(gè)位置有緊密的關(guān)聯(lián)關(guān)系,交換一下,他的存儲(chǔ)結(jié)構(gòu)就被破壞了。順序容器中的元素是按關(guān)鍵字來(lái)保存和訪問(wèn)的。關(guān)聯(lián)式容器有map/set系列和unordered_map/unordered_set系列。

mapset底層是紅黑樹(shù),紅黑樹(shù)是一顆平衡二叉搜索樹(shù)。setkey搜索場(chǎng)景的結(jié)構(gòu),mapkey/value搜索場(chǎng)景的結(jié)構(gòu)。
說(shuō)人話 就是map set的值不能改 改了結(jié)構(gòu)會(huì)被破壞。

2. set系列的使用

2.1 set類(lèi)的介紹

  • set的聲明如下,T就是set底層關(guān)鍵字的類(lèi)型
  • set默認(rèn)要求T支持小于比較,如果不支持或者想按自己的需求走可以自行實(shí)現(xiàn)仿函數(shù)傳給第二個(gè)模版參數(shù)。
  • set底層存儲(chǔ)數(shù)據(jù)的內(nèi)存是從空間配置器申請(qǐng)的,如果需要可以自己實(shí)現(xiàn)內(nèi)存池,傳給第三個(gè)參數(shù)。
  • 一般情況下,我們都不需要傳后兩個(gè)模版參數(shù)。
  • set底層是用紅黑樹(shù)實(shí)現(xiàn),增刪查效率是 O ( l o g N ) O(logN) O(logN),迭代器遍歷是走的搜索樹(shù)的中序,所以是有序的。
  • vector/list等容器的使用,STL容器接口設(shè)計(jì),高度相似,所以這里我們就不再一個(gè)接口一個(gè)接口的介紹,挑比較重要的接口進(jìn)行介紹。

2.2 set的構(gòu)造和迭代器

0.構(gòu)造:

set 的支持正向和反向迭代遍歷,遍歷默認(rèn)按升序順序,因?yàn)榈讓邮嵌嫠阉鳂?shù),迭代器遍歷走的中序;支持迭代器就意味著支持范圍 for,setiteratorconst_iterator 都不支持迭代器修改數(shù)據(jù),修改關(guān)鍵字?jǐn)?shù)據(jù),防止破壞底層搜索樹(shù)的結(jié)構(gòu)。

1. 空構(gòu)造(empty (1))

explicit set (const key_compare& comp = key_compare(),
               const allocator_type& alloc = allocator_type());
  • 作用:創(chuàng)建空的set容器。
  • 參數(shù)
    • comp:可選,自定義的鍵比較規(guī)則(默認(rèn)使用key_compare,即<比較);
    • alloc:可選,內(nèi)存分配器(默認(rèn)使用allocator_type)。

2. 范圍構(gòu)造(range (2))

template <class InputIterator>
set (InputIterator first, InputIterator last,
     const key_compare& comp = key_compare(),
     const allocator_type& alloc = allocator_type());
  • 作用:將迭代器[first, last)范圍內(nèi)的元素插入set(自動(dòng)去重并按規(guī)則排序)。
  • 參數(shù)
    • first/last:輸入迭代器,指定待插入元素的范圍;
    • comp/alloc:同空構(gòu)造的可選參數(shù)。

3. 拷貝構(gòu)造(copy (3))

set (const set& x);
  • 作用:創(chuàng)建一個(gè)與已有set對(duì)象x內(nèi)容完全相同的新set。

4. 初始化列表(C++11)

void test_set1()
{
    set<int> s = { 5,1,5,3,4,2,6,83,9,10,22 };
    // 中序,排序+去重
    set<int>::iterator it = s.begin();
    while (it != s.end())
    {
        // 普通迭代器也不支持修改
        // *it = 1;
        
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}

2.3 修改器(Modifiers)的成員函數(shù)


這是C++ std::set修改器(Modifiers)成員函數(shù),負(fù)責(zé)對(duì)set的元素進(jìn)行增刪等操作。以下結(jié)合代碼示例逐一講解:

0. 迭代器

這個(gè)太基礎(chǔ)了 我個(gè)人感覺(jué)實(shí)在沒(méi)什么可以說(shuō)的 唯一要注意的就是 不能通過(guò)迭代器修改里面的值。

1. insert:插入元素

功能:向set中插入鍵值(自動(dòng)去重、按規(guī)則排序)。
代碼示例

#include <set>
#include <iostream>
using namespace std;

int main() {
    set<int> s;
    // 插入單個(gè)元素
    s.insert(3);
    s.insert(1);
    s.insert(2);
    s.insert(2); // 重復(fù)元素,插入失?。╯et自動(dòng)去重)

    // 遍歷輸出:1 2 3(默認(rèn)升序)
    for (int val : s) cout << val << " ";
    return 0;
}

2. erase:刪除元素

功能:刪除set中的元素(支持按鍵值、迭代器、范圍刪除)。
代碼示例

int main() {
    set<int> s = {1,2,3,4,5};
    // 1. 按鍵值刪除
    s.erase(3); 
    // 2. 按迭代器刪除
    auto it = s.find(4);
    if (it != s.end()) s.erase(it);
    // 3. 按范圍刪除(刪除[begin, end))
    s.erase(s.begin(), s.end()); //左閉右開(kāi)

    cout << s.size(); // 輸出0
    return 0;
}

3. swap:交換兩個(gè)set的內(nèi)容(與算法庫(kù)swap對(duì)比)

功能:交換當(dāng)前set與另一個(gè)set的所有元素(底層僅交換內(nèi)部指針,效率高,而算法庫(kù)swap則涉及深層拷貝等)。
代碼示例

int main() {
    set<int> s1 = {1,2,3};
    set<int> s2 = {4,5,6};
    s1.swap(s2);

    // s1變?yōu)閧4,5,6},s2變?yōu)閧1,2,3}
    for (int val : s1) cout << val << " "; // 輸出4 5 6
    return 0;
}

4. clear:清空所有元素

功能:刪除set中的所有元素,使其變?yōu)榭杖萜鳌?br />代碼示例

int main() {
    set<int> s = {1,2,3};
    s.clear();
    cout << s.empty(); // 輸出1(表示容器為空)
    return 0;
}

5. emplace:構(gòu)造并插入元素(C++11+)

功能:直接在set中構(gòu)造元素(避免臨時(shí)對(duì)象拷貝,比insert更高效)。
代碼示例

int main() {
    set<pair<int, string>> s;
    // emplace直接構(gòu)造pair(無(wú)需手動(dòng)創(chuàng)建臨時(shí)pair)
    s.emplace(1, "apple"); 
    // 等價(jià)于insert,但emplace更高效
    s.insert(pair<int, string>(2, "banana"));

    return 0;
}

6. emplace_hint:帶位置提示的構(gòu)造插入(C++11+)

功能:在指定迭代器位置附近構(gòu)造并插入元素(若位置合理,可提升插入效率)。
代碼示例

int main() {
    set<int> s = {1,3,5};
    // 提示在3的位置附近插入2(實(shí)際插入到1和3之間)
    auto it = s.find(3);
    s.emplace_hint(it, 2);

    for (int val : s) cout << val << " "; // 輸出1 2 3 5
    return 0;
}

2.4 find(與算法庫(kù)find的對(duì)比)

這是C++標(biāo)準(zhǔn)庫(kù)中std::set::find成員函數(shù)的聲明(支持C++98及以上版本),其核心信息與使用說(shuō)明如下:

iterator find (const value_type& val) const;
  • 返回值iteratorset的迭代器),指向找到的鍵值val;若val不存在,返回set::end()(尾后迭代器)。
  • 參數(shù)const value_type& val,待查找的鍵值(value_typeset的關(guān)鍵字類(lèi)型)。
  • 特性const修飾表示該函數(shù)不會(huì)修改set本身。

findset查找接口,基于底層紅黑樹(shù)的特性,能以 O ( log ? N ) O(\log N) O(logN)的時(shí)間復(fù)雜度快速定位鍵值,常用于判斷元素是否存在、獲取元素迭代器。

  • 效率:由于set底層是有序的紅黑樹(shù),find通過(guò)二分查找邏輯實(shí)現(xiàn),效率遠(yuǎn)高于算法庫(kù)的find O ( N ) O(N) O(N))。
  • 迭代器特性:set的迭代器是雙向迭代器,且不可修改(因?yàn)樾薷逆I值會(huì)破壞set的有序性)。
#include <set>
#include <iostream>
using namespace std;

int main() {
    set<int> s = {1, 2, 3, 4, 5};
    
    // 查找鍵值3
    auto it = s.find(3);
    if (it != s.end()) {
        cout << "找到元素:" << *it << endl; // 輸出“找到元素:3”
    }

    // 查找不存在的鍵值6
    it = s.find(6);
    if (it == s.end()) {
        cout << "未找到元素" << endl; // 輸出“未找到元素”
    }

    return 0;
}

2.5 key_comp && value_comp

函數(shù)名功能描述
key_comp返回set用于比較**鍵(key)**的函數(shù)對(duì)象,是set模板參數(shù)中指定的比較類(lèi)型(默認(rèn)是less<key_type>)。
value_comp功能與key_comp一致(因?yàn)閟et的鍵和值是同一類(lèi)型),返回的比較對(duì)象邏輯等同于key_comp。

set的底層紅黑樹(shù)依賴(lài)比較規(guī)則維持有序性,這兩個(gè)函數(shù)可以獲取當(dāng)前set使用的比較邏輯,常用于:

  1. 自定義比較規(guī)則時(shí),驗(yàn)證或復(fù)用set的排序邏輯;
  2. 對(duì)set的元素進(jìn)行外部排序(保持與set內(nèi)部一致的規(guī)則)。

代碼示例

#include <set>
#include <iostream>
using namespace std;

int main() {
    // 定義一個(gè)按降序排序的set
    set<int, greater<int>> s = {3, 1, 2};

    // 獲取key_comp比較對(duì)象
    auto comp = s.key_comp();

    // 使用comp判斷兩個(gè)鍵的大小關(guān)系(符合set的降序規(guī)則)
    bool res = comp(1, 2); // 等價(jià)于greater<int>()(1,2),結(jié)果為false
    cout << "1 > 2 ? " << boolalpha << res << endl; // 輸出“1 > 2 ? false”

    return 0;
}

2.6 count(與find比較)

  • 聲明size_type count (const value_type& val) const;
  • 功能:統(tǒng)計(jì)set中值為val的元素個(gè)數(shù)(由于set不允許重復(fù)元素,返回值只能是01)。
  • 參數(shù)const value_type& val,待統(tǒng)計(jì)的目標(biāo)值;
  • 返回值size_type(無(wú)符號(hào)整數(shù)類(lèi)型),表示valset中的出現(xiàn)次數(shù)。

由于set的“唯一性”特性,count的實(shí)際作用是判斷元素是否存在(返回1表示存在,0表示不存在),效果等價(jià)于find(val) != end(),但語(yǔ)義更偏向“計(jì)數(shù)”。

#include <set>
#include <iostream>
using namespace std;

int main() {
    set<int> s = {1, 2, 3, 4};

    // 統(tǒng)計(jì)存在的元素
    size_t cnt1 = s.count(3);
    cout << "元素3的出現(xiàn)次數(shù):" << cnt1 << endl; // 輸出1

    // 統(tǒng)計(jì)不存在的元素
    size_t cnt2 = s.count(5);
    cout << "元素5的出現(xiàn)次數(shù):" << cnt2 << endl; // 輸出0

    return 0;
}

與find的區(qū)別

函數(shù)功能返回值類(lèi)型適用場(chǎng)景
find查找元素并返回迭代器迭代器需要獲取元素的位置時(shí)
count統(tǒng)計(jì)元素出現(xiàn)次數(shù)無(wú)符號(hào)整數(shù)僅需判斷元素是否存在時(shí)

綜合對(duì)比 在判斷元素是否存在時(shí) count 更加方便!

2.7 lower_bound && upper_bound

函數(shù)名功能描述
lower_bound返回指向**第一個(gè)不小于(≥)目標(biāo)值val**的元素的迭代器;若所有元素都小于val,返回end()。
upper_bound返回指向**第一個(gè)大于(>)目標(biāo)值val**的元素的迭代器;若所有元素都不大于val,返回end()。

由于set是有序容器(默認(rèn)升序),這兩個(gè)函數(shù)通過(guò)二分查找(時(shí)間復(fù)雜度 O ( log ? N ) O(\log N) O(logN))快速定位邊界,常用于獲取“等于val的元素區(qū)間”([lower_bound, upper_bound))。

#include <set>
#include <iostream>
using namespace std;

int main() {
    set<int> s = {1, 3, 5, 7, 9};
    int val = 5;

    // 獲取lower_bound:第一個(gè)≥5的元素(即5)
    auto lb = s.lower_bound(val);
    cout << "lower_bound(" << val << "): " << *lb << endl; // 輸出5

    // 獲取upper_bound:第一個(gè)>5的元素(即7)
    auto ub = s.upper_bound(val);
    cout << "upper_bound(" << val << "): " << *ub << endl; // 輸出7

    // 若val不存在(如val=4)
    val = 4;
    lb = s.lower_bound(val); // 第一個(gè)≥4的元素是5
    ub = s.upper_bound(val); // 第一個(gè)>4的元素是5
    cout << "val=4時(shí),[lb, ub)區(qū)間長(zhǎng)度:" << distance(lb, ub) << endl; // 輸出0(無(wú)元素)

    return 0;
}

用處: 刪除或者遍歷 某一區(qū)間的值:

3. multiset

multisetset,核心差異集中在元素唯一性、接口行為、使用場(chǎng)景三個(gè)維度,但是multiset不用單獨(dú)包含頭文件,二者基本完全類(lèi)似。

3.1 核心特性差異

維度setmultiset
元素唯一性不允許重復(fù)元素(鍵唯一)允許重復(fù)元素(鍵可重復(fù))
底層實(shí)現(xiàn)紅黑樹(shù)(平衡二叉搜索樹(shù))紅黑樹(shù)(平衡二叉搜索樹(shù))
有序性元素按鍵有序排列元素按鍵有序排列

3.2 接口行為差異

以常用成員函數(shù)為例,兩者行為因“唯一性”產(chǎn)生區(qū)別:

接口set的行為multiset的行為
insert插入重復(fù)元素時(shí)返回失?。▋H插入一次)插入重復(fù)元素時(shí)成功(可插入多次)
find返回第一個(gè)匹配鍵的迭代器返回第一個(gè)匹配鍵的迭代器(切記是中序遍歷的第一個(gè))
count返回0或1(僅表示存在性)返回鍵的實(shí)際出現(xiàn)次數(shù)
lower_bound/upper_bound區(qū)間[lb, ub)長(zhǎng)度最多為1區(qū)間[lb, ub)包含所有匹配鍵的元素
erase按鍵刪除時(shí),刪除所有匹配的元素(僅1個(gè))按鍵刪除時(shí),刪除所有匹配的元素(可能多個(gè))

3.3 使用場(chǎng)景差異

  • set:適用于需要唯一鍵的場(chǎng)景(如存儲(chǔ)不重復(fù)的ID、去重后的數(shù)據(jù)集);
  • multiset:適用于需要統(tǒng)計(jì)鍵出現(xiàn)次數(shù)的場(chǎng)景(如統(tǒng)計(jì)單詞頻率、存儲(chǔ)可重復(fù)的有序數(shù)據(jù))。
#include <set>
#include <iostream>
using namespace std;

int main() {
    // set:鍵唯一
    set<int> s = {1, 2, 2, 3};
    cout << "set大小:" << s.size() << endl; // 輸出3(自動(dòng)去重)

    // multiset:鍵可重復(fù)
    multiset<int> ms = {1, 2, 2, 3};
    cout << "multiset大?。? << ms.size() << endl; // 輸出4(保留重復(fù))

    // count接口差異
    cout << "set中2的數(shù)量:" << s.count(2) << endl; // 輸出1
    cout << "multiset中2的數(shù)量:" << ms.count(2) << endl; // 輸出2

    return 0;
}

4. 例題部分

4.1 環(huán)形鏈表 II

題目鏈接: 點(diǎn)此跳轉(zhuǎn)

我們之前C語(yǔ)言階段是使用快慢指針完成的 其實(shí)我們可以用ste<Node*> s來(lái)做 遍歷鏈表,每個(gè)節(jié)點(diǎn)是否在s中,不在就插入,在的第一個(gè)點(diǎn)就是入口點(diǎn) , 要說(shuō)這道題唯一的缺陷 就是有 O ( N ) O(N) O(N)的空間復(fù)雜度。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode* head) 
    {
        set<ListNode*> s;
        ListNode* tmp=head;
        while(tmp!=NULL)
        {
            if(s.count(tmp)==0)
            {
                s.insert(tmp);
                tmp=tmp->next;
            }
            else
            {
                return tmp;
            }
        }
        return NULL;
    }
};

4.2 兩個(gè)數(shù)組的交集

題目鏈接: 點(diǎn)此轉(zhuǎn)跳

這題也挺簡(jiǎn)單的 其實(shí)就是拿set去重就可以了 然后用一個(gè)set的count去遍歷另一個(gè)set 把重復(fù)的插入vector即可。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
    {
     //去重 
     set<int> s1(nums1.begin(),nums1.end());  
     set<int> s2(nums2.begin(),nums2.end());  
     vector<int> v;
     for(auto e : s1)
     {
        if(s2.count(e))
        {
            v.push_back(e);
        }
     }
     return v;
    }
};

補(bǔ)充
這么做 其實(shí)復(fù)雜度還是高的 因?yàn)?code>count的特性 時(shí)間復(fù)雜度可能要 O ( N ∗ l o g N ) O(N*logN) O(NlogN)
但是利用雙指針特性就可以把復(fù)雜度壓縮到 O ( N ) O(N) O(N)。這個(gè)方法不光能找交集,也能找差集。

到此這篇關(guān)于C++ set和multiset的使用小結(jié)的文章就介紹到這了,更多相關(guān)C++ set和multiset內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

衡山县| 旬阳县| 安多县| 依兰县| 图木舒克市| 崇文区| 灵武市| 通渭县| 新邵县| 霍邱县| 阜新市| 乌兰县| 蒲江县| 宁海县| 天水市| 泸定县| 辉南县| 江北区| 高邮市| 龙胜| 南乐县| 静海县| 胶州市| 五大连池市| 仪征市| 建水县| 营口市| 宾阳县| 保定市| 博爱县| 沙坪坝区| 逊克县| 中江县| 邵阳市| 金阳县| 乌鲁木齐县| 新宁县| 博白县| 武功县| 土默特右旗| 荥阳市|