【C++進階】關聯容器:set類型

目錄

一、set 基本概念

1.1 定義與特點

1.2 頭文件與聲明

1.3 核心特性解析

二、set 底層實現

2.1 紅黑樹簡介

2.2 紅黑樹在 set 中的應用

三、set 常用操作

3.1 插入元素

3.2 刪除元素

3.3 查找元素

3.4 遍歷元素

3.5 性能特征

四、set 高級應用

4.1 自定義比較函數

4.2 交集、并集和差集操作

4.3 與其他容器的結合使用

4.4?迭代器操作

4.5?性能優化技巧

五、set 與其他容器的比較

5.1 set 與 vector

5.2 set 與 unordered_set

5.3 選擇建議

六、注意事項與常見錯誤

6.1 迭代器失效問題

6.2 性能考慮

6.3 內存占用

6.4?易錯點提醒

七、應用場景與實戰案例

八、總結

九、參考資料


在 C++ 編程中,容器是非常重要的工具,它可以幫助我們高效地管理和操作數據。關聯容器是 C++ 標準模板庫(STL)中的一類特殊容器,它們通過鍵(key)來存儲和訪問元素。set?作為關聯容器的一種,在很多場景下都有著廣泛的應用。本文將全面深入地介紹?set?類型,包括其基本概念、底層實現、常用操作、高級應用以及與其他容器的比較等內容。

一、set 基本概念

1.1 定義與特點

set?是一種關聯容器,它用于存儲唯一的元素,并且這些元素會根據其值自動進行排序。在?set?中,鍵(key)和值(value)是相同的,即每個元素既是鍵也是值。由于?set?不允許有重復的元素,因此插入重復元素時會被忽略。

1.2 頭文件與聲明

要使用?set,需要包含?<set>?頭文件。以下是一個簡單的?set?聲明示例:

#include <iostream>
#include <set>int main() {std::set<int> mySet; // 聲明一個存儲 int 類型元素的 setreturn 0;
}

1.3 核心特性解析

std::set是基于紅黑樹實現的有序關聯容器,其設計目標是通過平衡二叉搜索樹結構,在保證元素唯一性的同時,實現以下核心特性:

①自動排序機制

  • 插入元素時自動按升序排列
  • 默認使用<運算符比較元素
  • 支持自定義比較函數

②唯一性約束

  • 不允許重復元素
  • 插入重復值時自動去重

③對數時間復雜度操作

  • 插入:O(log n)
  • 刪除:O(log n)
  • 查找:O(log n)

④內存動態管理

  • 自動處理內存分配/釋放
  • 支持迭代器失效保護

二、set 底層實現

2.1 紅黑樹簡介

set?通常使用紅黑樹(Red-Black Tree)作為底層數據結構。紅黑樹是一種自平衡的二叉搜索樹,它通過對節點進行著色(紅色或黑色)并遵循一些特定的規則來保持樹的平衡,從而保證了插入、刪除和查找操作的時間復雜度都是?O(logn)。

紅黑樹的主要特性包括:

  • 每個節點要么是紅色,要么是黑色。
  • 根節點是黑色。
  • 每個葉子節點(NIL 節點,空節點)是黑色。
  • 如果一個節點是紅色的,則它的兩個子節點都是黑色的。
  • 對每個節點,從該節點到其所有后代葉節點的簡單路徑上,均包含相同數目的黑色節點。

2.2 紅黑樹在 set 中的應用

在?set?中,紅黑樹的節點存儲了?set?中的元素。當插入一個新元素時,set?會根據元素的值將其插入到紅黑樹的合適位置,并通過旋轉和著色操作來保持樹的平衡。查找元素時,set?會從根節點開始,根據元素的值與節點的值進行比較,然后遞歸地在左子樹或右子樹中查找,直到找到目標元素或到達葉子節點。

三、set 常用操作

3.1 插入元素

可以使用?insert()?函數向?set?中插入元素。如果插入的元素已經存在于?set?中,則插入操作會被忽略。

#include <iostream>
#include <set>int main() {std::set<int> mySet;mySet.insert(3);mySet.insert(1);mySet.insert(2);for (const auto& element : mySet) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

輸出:1 2 3,因為?set?會自動對元素進行排序。

3.2 刪除元素

可以使用?erase()?函數從?set?中刪除元素。erase()?函數有多種重載形式,可以根據元素的值或迭代器來刪除元素。

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};mySet.erase(3); // 根據元素的值刪除auto it = mySet.find(4);if (it != mySet.end()) {mySet.erase(it); // 根據迭代器刪除}for (const auto& element : mySet) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

3.3 查找元素

可以使用?find()?函數在?set?中查找元素。如果找到元素,則返回指向該元素的迭代器;如果未找到,則返回?end()?迭代器。

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};auto it = mySet.find(3);if (it != mySet.end()) {std::cout << "Found: " << *it << std::endl;} else {std::cout << "Not found" << std::endl;}return 0;
}

3.4 遍歷元素

可以使用范圍?for?循環或迭代器來遍歷?set?中的元素。

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};// 使用范圍 for 循環遍歷for (const auto& element : mySet) {std::cout << element << " ";}std::cout << std::endl;// 使用迭代器遍歷for (auto it = mySet.begin(); it != mySet.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}

3.5 性能特征

操作時間復雜度說明
insert()O(log n)插入新元素
erase()O(log n)刪除元素
find()O(log n)查找元素
count()O(log n)統計元素出現次數
size()O(1)獲取元素數量
empty()O(1)檢查是否為空

四、set 高級應用

4.1 自定義比較函數

默認情況下,set?使用?std::less?作為比較函數來對元素進行排序。如果需要自定義排序規則,可以在聲明?set?時提供自定義的比較函數。

#include <iostream>
#include <set>// 自定義比較函數,實現降序排序
struct Greater {bool operator()(const int& a, const int& b) const {return a > b;}
};int main() {std::set<int, Greater> mySet = {1, 2, 3, 4, 5};for (const auto& element : mySet) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

4.2 交集、并集和差集操作

可以使用?<algorithm>?頭文件中的?set_intersection()set_union()?和?set_difference()?函數來實現?set?的交集、并集和差集操作。

#include <iostream>
#include <set>
#include <algorithm>
#include <vector>int main() {std::set<int> set1 = {1, 2, 3, 4, 5};std::set<int> set2 = {3, 4, 5, 6, 7};std::vector<int> intersection;std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(intersection));std::cout << "Intersection: ";for (const auto& element : intersection) {std::cout << element << " ";}std::cout << std::endl;std::vector<int> unionSet;std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(unionSet));std::cout << "Union: ";for (const auto& element : unionSet) {std::cout << element << " ";}std::cout << std::endl;std::vector<int> difference;std::set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(difference));std::cout << "Difference (set1 - set2): ";for (const auto& element : difference) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

4.3 與其他容器的結合使用

set?可以與其他容器(如?vectorlist?等)結合使用,以實現更復雜的功能。例如,可以將?vector?中的元素插入到?set?中進行去重和排序。

#include <iostream>
#include <set>
#include <vector>int main() {std::vector<int> vec = {3, 1, 2, 3, 4, 2};std::set<int> mySet(vec.begin(), vec.end());for (const auto& element : mySet) {std::cout << element << " ";}std::cout << std::endl;return 0;
}

4.4?迭代器操作

std::set<int> s = {1, 3, 5, 7, 9};// 反向迭代器
std::cout << "反向遍歷: ";
for (auto rit = s.rbegin(); rit != s.rend(); ++rit) {std::cout << *rit << " ";
}// 迭代器失效處理
auto it = s.find(5);
s.erase(it); // 迭代器失效,不可繼續使用

4.5?性能優化技巧

批量插入優化:

std::set<int> s;
s.insert({1, 2, 3, 4, 5}); // C++11初始化列表優化

emplace原位構造:

s.emplace(10); // 直接在容器內構造對象,避免臨時對象拷貝

預留空間(C++11起):?

s.reserve(100); // 預分配內存減少重分配次數

五、set 與其他容器的比較

操作setunordered_setvector有序
插入O(log n)O(1)平均O(n)
查找O(log n)O(1)平均O(log n)二分
刪除O(log n)O(1)平均O(n)
內存占用較高較低緊湊
有序性始終有序無序需排序

5.1 set 與 vector

  • 存儲方式vector?是一種順序容器,它使用連續的內存空間存儲元素;而?set?是一種關聯容器,使用紅黑樹存儲元素。
  • 元素特性vector?允許有重復的元素,并且元素的順序是按照插入的順序排列的;set?不允許有重復的元素,并且元素會自動排序。
  • 查找效率vector?的查找操作的時間復雜度為?O(n),而?set?的查找操作的時間復雜度為?O(logn)。

5.2 set 與 unordered_set

  • 底層實現set?使用紅黑樹作為底層數據結構,而?unordered_set?使用哈希表作為底層數據結構。
  • 排序特性set?中的元素會自動排序,而?unordered_set?中的元素是無序的。
  • 查找效率unordered_set?的查找操作的平均時間復雜度為?O(1),而?set?的查找操作的時間復雜度為?O(logn)。

5.3 選擇建議

  • 如果需要存儲唯一的元素并且要求元素有序,那么可以選擇?set
  • 如果只需要存儲唯一的元素,不關心元素的順序,并且對查找效率有較高的要求,那么可以選擇?unordered_set
  • 如果需要存儲多個相同的元素,并且對元素的順序有要求,那么可以選擇?vector

六、注意事項與常見錯誤

6.1 迭代器失效問題

在對?set?進行插入或刪除操作時,可能會導致迭代器失效。例如,在刪除一個元素后,指向該元素的迭代器將失效。因此,在使用迭代器時,需要特別注意避免迭代器失效的問題。

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 2, 3, 4, 5};auto it = mySet.find(3);if (it != mySet.end()) {mySet.erase(it); // 刪除元素后,it 迭代器失效// 不能再使用 it 迭代器}return 0;
}

6.2 性能考慮

雖然?set?的插入、刪除和查找操作的時間復雜度都是?O(logn),但在某些情況下,可能會有性能瓶頸。例如,當需要頻繁插入和刪除元素時,紅黑樹的旋轉和著色操作可能會影響性能。此時,可以考慮使用?unordered_set?來提高性能。

6.3 內存占用

由于?set?使用紅黑樹作為底層數據結構,它需要額外的內存來存儲節點的指針和顏色信息。因此,在對內存占用有嚴格要求的場景下,需要謹慎使用?set

6.4?易錯點提醒

修改元素值:直接修改元素會導致未定義行為

auto it = s.begin();
// *it = 10;  // 錯誤!元素是const的

迭代器失效:僅刪除操作會使指向被刪元素的迭代器失效

自定義比較函數:需保證嚴格弱序關系

// 錯誤示例:未實現嚴格弱序
struct BadCompare {bool operator()(int a, int b) {return a <= b;  // 應該用<}
};

七、應用場景與實戰案例

案例1:數據去重排序

std::vector<int> nums = {5, 2, 5, 1, 3, 2};
std::set<int> unique_nums(nums.begin(), nums.end());// 輸出:1 2 3 5
for(int num : unique_nums) {std::cout << num << " ";
}

案例2:字典序管理

std::set<std::string> dictionary;void add_word(const std::string& word) {dictionary.insert(word);
}bool check_spelling(const std::string& word) {return dictionary.count(word);
}

八、總結

set作為STL中的有序唯一集合容器,在需要維護有序數據且保證元素唯一性的場景中表現卓越。通過紅黑樹實現的高效操作使其成為處理排序、去重、快速查找等需求的理想選擇。掌握set的特性和正確使用方式,將顯著提升C++編程能力。

九、參考資料

  • ?《C++ Primer(第 5 版)》這本書是 C++ 領域的經典之作,對 C++ 的基礎語法和高級特性都有深入講解。
  • 《Effective C++(第 3 版)》書中包含了很多 C++ 編程的實用建議和最佳實踐。
  • 《C++ Templates: The Complete Guide(第 2 版)》該書聚焦于 C++ 模板編程,而using聲明在模板編程中有著重要應用,如定義模板類型別名等。
  • C++ 官方標準文檔:C++ 標準文檔是最權威的參考資料,可以查閱最新的 C++ 標準(如 C++11、C++14、C++17、C++20 等)文檔。例如,ISO/IEC 14882:2020 是 C++20 標準的文檔,可從相關渠道獲取其詳細內容。
  • :這是一個非常全面的 C++ 在線參考網站,提供了詳細的 C++ 語言和標準庫文檔。
  • :該網站提供了系統的 C++ 教程,配有豐富的示例代碼和清晰的解釋,適合初學者學習和理解相關知識。
  • 《Effective STL》Scott Meyers

  • 開源項目STL源碼分析


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/76200.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/76200.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/76200.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[漏洞篇]SSRF漏洞詳解

[漏洞篇]SSRF漏洞詳解 免責聲明&#xff1a; 本文主要講解漏洞原理&#xff0c;以及防御手段&#xff0c;旨在幫助大家更好的了解漏洞危害&#xff0c;以及開發中所需要的點&#xff0c;切勿拿來做違法事情&#xff0c;否則后果自負。 一、介紹 概念 SSRF&#xff1a;服務端請…

nuscenes數據集分析

nuscenes數據集分析 標注與總體介紹 nuscenes包含有相機、激光雷達、毫米波雷達、IMU與GPS等設備提供的數據。它的數據采集了1000個場景&#xff0c;每個場景大約有20s&#xff0c;針對目標檢測任務&#xff0c;對23類物體進行標注&#xff0c;且以2Hz的頻率提供精確的三維目標…

JavaScript學習教程,從入門到精通,JavaScript 運算符及語法知識點詳解(8)

JavaScript 運算符及語法知識點詳解 一、JavaScript 運算符 1. 算術運算符 用于執行數學運算&#xff1a; 加法- 減法* 乘法/ 除法% 取模&#xff08;余數&#xff09; 遞增-- 遞減** 冪運算&#xff08;ES6&#xff09; let a 10, b 3; console.log(a b); // 13 conso…

Shell腳本的學習

編寫腳本文件 定義以開頭&#xff1a;#!/bin/bash #!用來聲明腳本由什么shell解釋&#xff0c;否則使用默認shel 第一步&#xff1a;編寫腳本文件 #!/bin/bash #注釋 echo "這是輸出" 第二步&#xff1a;加上執行權限&#xff1a;chmod x 腳本文件名.sh 第三步&…

在線PDF文件拆分工具,小白工具功能實用操作簡單,無需安裝的文檔處理工具

小白工具中的在線 PDF 文件拆分工具是一款功能實用、操作便捷的文檔處理工具&#xff0c;以下是其具體介紹&#xff1a; 操作流程 上傳 PDF 文檔&#xff1a;打開小白工具在線PDF文件拆分工具 - 快速、免費拆分PDF文檔 - 小白工具的在線 PDF 文件拆分頁面&#xff0c;通過點擊 …

數字的乘階運算

求數字的乘階&#xff1a; 例如&#xff1a;6的乘階運算&#xff1a;6*5*4*3*2*1 例如&#xff1a;3的乘階運算&#xff1a;3*2*1 class Program{static void Main(string[] args){Console.WriteLine("請輸入數字&#xff1a;");int num_01 Convert.ToInt32 (Con…

tcp/ip攻擊及防范

作為高防工程師&#xff0c;我每天攔截數以萬計的惡意流量&#xff0c;其中TCP/IP協議層攻擊是最隱蔽、最具破壞性的威脅之一。常見的攻擊手法包括&#xff1a; 1. SYN Flood攻擊&#xff1a;攻擊者發送大量偽造的SYN包&#xff0c;耗盡服務器連接資源&#xff0c;導致正常用…

C++類成員內存分布詳解

本文將探討C類中成員變量的內存分布情況&#xff0c;包括普通成員、靜態成員、虛函數等不同情況下的內存布局。 一、基本成員內存布局 1. 普通成員變量 普通成員變量按照聲明順序在內存中連續排列&#xff08;受訪問修飾符和內存對齊影響&#xff09;&#xff1a; class Nor…

計算機視覺——為什么 mAP 是目標檢測的黃金標準

概述 在目標檢測領域&#xff0c;有一個指標被廣泛認為是衡量模型性能的“黃金標準”&#xff0c;它就是 mAP&#xff08;Mean Average Precision&#xff0c;平均精確率均值&#xff09;。如果你曾經接觸過目標檢測模型&#xff08;如 YOLO、Faster R-CNN 或 SSD&#xff09;…

C語言單鏈表的增刪改補

目錄 &#xff08;一&#xff09;單鏈表的結構定義及初始化 (二)單鏈表的尾插&#xff0c;頭插 (三)單鏈表的尾刪&#xff0c;頭刪 (四)單鏈表的查找&#xff0c;刪除&#xff0c;銷毀 單鏈表是數據結構課程里的第二個數據結構。單鏈表在邏輯結構是連續的&#xff0c;在物理…

Android10.0 framework第三方無源碼APP讀寫斷電后數據丟失問題解決

1.前言 在10.0中rom定制化開發中,在某些產品開發中,在某些情況下在App用FileOutputStream讀寫完畢后,突然斷電 會出現寫完的數據丟失的問題,接下來就需要分析下關于使用FileOutputStream讀寫數據的相關流程,來實現相關 功能 2.framework第三方無源碼APP讀寫斷電后數據丟…

殺戮尖塔(Slay The Spire) 的全新角色模組 - 女巫

女巫&#xff08;The Witch&#xff09; 殺戮尖塔&#xff08;Slay The Spire&#xff09; 的全新角色模組 女巫模組為游戲增添了超過 75 張新卡牌和 4 個全新遺物&#xff0c;圍繞 詛咒&#xff08;Curses&#xff09; 展開獨特的玩法體驗。她的起始遺物 黑貓&#xff08;Bl…

AI開發學習路線(闖關升級版)

以下是一份輕松版AI開發學習路線&#xff0c;用「闖關升級」的方式幫你從零開始變身AI開發者&#xff0c;每個階段都配有有趣的任務和實用資源&#xff0c;保證不枯燥、可落地&#xff01;&#x1f447; 目錄 &#x1f530; 新手村&#xff1a;打基礎&#xff08;1-2個月&…

迭代器模式深度解析與實戰案例

一、模式定義 迭代器模式&#xff08;Iterator Pattern&#xff09; 是一種行為設計模式&#xff0c;提供一種方法順序訪問聚合對象的元素&#xff0c;無需暴露其底層表示。核心思想是將遍歷邏輯從聚合對象中分離&#xff0c;實現 遍歷與存儲的解耦。 二、核心組件 組件作用…

SSH遠程工具

一、常見SSH遠程工具 工具開源跨平臺多標簽文件傳輸高級功能價格Xshell?Win????腳本、會話管理免費/商業版Tabby??全平臺????插件擴展免費MobaXterm?Win????集成工具集免費/付費SecureCRT?Win/macOS/Linux????企業級加密$129+PuTTY??全平臺??基礎連接…

VUE中的路由處理

1.引入,預處理main.ts import {} from vue-router import { createRouter, createWebHistory } from vue-router import HomePages from @/pages/HomePages.vue import AboutPage from @/pages/AboutPage.vue import NewsPage from @/pages/NewsPage.vue //1. 配置路由規…

編程助手fitten code使用說明(超詳細)(vscode)

這兩年 AI 發展迅猛&#xff0c;作為開發人員&#xff0c;我們總是追求更快、更高效的工作方式&#xff0c;AI 的出現可以說改變了很多人的編程方式。 AI 對我們來說就是一個可靠的編程助手&#xff0c;給我們提供了實時的建議和解決方&#xff0c;無論是快速修復錯誤、提升代…

Opencv計算機視覺編程攻略-第九節 描述和匹配興趣點

一般而言&#xff0c;如果一個物體在一幅圖像中被檢測到關鍵點&#xff0c;那么同一個物體在其他圖像中也會檢測到同一個關鍵點。圖像匹配是關鍵點的常用功能之一&#xff0c;它的作用包括關聯同一場景的兩幅圖像、檢測圖像中事物的發生地點等等。 1.局部模板匹配 憑單個像素就…

C++內存管理優化實戰:提升應用性能與效率

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家、CSDN平臺優質創作者&#xff0c;高級開發工程師&#xff0c;數學專業&#xff0c;擁有高級工程師證書&#xff1b;擅長C/C、C#等開發語言&#xff0c;熟悉Java常用開發技術&#xff0c;能熟練應用常用數據庫SQL server,Oracle…

17-產品經理-創建發布

點擊“發布”-“創建發布”。 填寫發布名稱&#xff0c;選擇測試的版本。還可以設置此次發布是否為“里程碑”。 點擊“保存”后&#xff0c;進入該發布詳情頁面。需要為此次發布關聯需求、已解決BUG、以及遺留BUG。可以通過設置條件&#xff0c;進行“搜索”&#xff0c;然后批…