【C++】認識map和set

目錄

前言:

一:認識map和set

二:map和set的使用

1.set的使用

2.map的使用?

三:map的insert方法返回值

四:map的[ ]的使用

五:multiset和multimap

六:map和set的底層數據結構

七:map和set的迭代器

總結:


前言:

我們通過之前的學習,已經學會了AVL樹和紅黑樹,但是STL中并沒有這兩種類,它是對紅黑樹進行了封裝,供上層使用的。

這里,我們就要先學會使用map和set了,是STL中的類模板,它們的底層都是紅黑樹。

一:認識map和set

大家有沒有想過,生活中很多東西都是一對一的。比如去停車場停車時,收費站會先記錄車牌號,之后一個車牌號對應一個存放時間;或者通訊錄中一個號碼對應一個聯系人等。這種方法就是鍵值對。一個唯一的鍵,對應一個唯一的值。但是你可以發現,這個值是可以修改的,而鍵不能修改。

比如一個老師要對每個學生管理,就要把每個學生學號管理起來,此時沒有用到值,只有鍵。

通過以上兩個例子,你就會發現,鍵都是唯一的,而值不是。這里再次說明,鍵也是不能修改的。

map中就是使用鍵值對的方式存儲;而set中只有鍵。

map中的值能修改,鍵不能修改;set中只有鍵,不能修改。

二:map和set的使用

既然我們知道了map存儲的是鍵值對,set存儲的是鍵,那么接下來,我們就要使用它們了。

1.set的使用

這個很簡單,引入<set>頭文件,之后可以去觀察cplusplus官網查看方法的使用(這里不是作者偷懶,而是我們到了現在這個階段,就必須學會看文檔了)。以下給出使用方法:

int main()
{set<int> s;s.insert(4);s.insert(6);s.insert(3);s.insert(5);set<int>::iterator it = s.begin();//auto it = s.begin();//底層是二叉搜索樹 默認中序遍歷while (it != s.end()){cout << *it << " ";++it;}cout << endl;//刪除最小值 也就是最左邊的迭代器指向的位置s.erase(s.begin());  //通過返回值判斷是否刪除成功int x;cin >> x;//int num = s.erase(x);//if (num == 0)//{//	cout << x << "不存在!" << endl;//}for (auto e : s){cout << e << " ";}cout << endl;set<int>::iterator pos = s.find(x);if (pos != s.end()){s.erase(pos);}else{cout << x << "不存在!" << endl;}for (auto e : s){cout << e << " ";}cout << endl;//使用算法頭文件的find查找auto pos1 = find(s.begin(), s.end(), x); //O(N) auto pos2 = s.find(x);                   //O(logN)//用find查找元素是否存在并不方便 使用count方便cin >> x;if (s.count(x)){cout << x << "在!" << endl;}else{cout << x << "不存在!" << endl;}return 0;
}

對沒錯,就這么多。

2.map的使用?

map存儲的是鍵值對,那么當然要有兩個模板參數,但是我們如何插入數據呢?

在此之前我們先來認識一個pair類:

可以發現它是一個結構體,兩個模板參數。

成員變量為:

對,很簡單,map就是存的它,但是對first加上了const修飾。接下來我們看看map的使用方法:

int main()
{map<string, string> dict;//我們要使用一個類向map中插入數據pair<string, string> kv1("left", "左邊");dict.insert(kv1);//傳入匿名對象dict.insert(pair<string, string>("right", "右邊"));//還有一個函數模板 make_pair 只用傳入鍵值對 就可以返回一個pair對象dict.insert(make_pair("insert", "插入"));//還有我們可以傳入多參數的初始化對象的方法dict.insert({ "string", "字符串" });map<string, string> dict1 = { {"left", "左邊"}, {"right", "右邊"} };map<string, string>::iterator it = dict.begin();while (it != dict.end()){//*it返回的是pair 但是其不支持流提取//cout << (*it) << endl;//可以去看pair 兩個成員變量 first 和 second//這里不是插入順序 而是字符ASCII碼排序 中序遍歷//cout << (*it).first << ":" << (*it).second << endl;cout << it->first << ":" << it->second << endl; //最好用第二種++it;}cout << endl; //用自定義類型寫范圍for遍歷map 最好這樣寫 不用深拷貝for (const auto& e : dict){cout << e.first << ":" << e.second << endl;}cout << endl;string arr[] = { "蘋果", "西瓜","蘋果","西瓜","蘋果" };map<string, int> Count;int tmp = 1;for (const auto& str : arr){//find返回的是迭代器auto ret = Count.find(str);//找到返回那個未知的迭代器 沒有找到返回endif (ret == Count.end()){//沒有這個元素Count.insert({str, 1});}else{++ret->second;}}auto it1 = Count.begin();while (it1 != Count.end()){//*it返回的是pair 但是其不支持流提取//cout << (*it) << endl;//可以去看pair 兩個成員變量 first 和 second//這里不是插入順序 而是字符ASCII碼排序 中序遍歷//cout << (*it).first << ":" << (*it).second << endl;cout << it1->first << ":" << it1->second << endl; //最好用第二種++it1;}return 0;
}

以上的insert方法我們需要注意,還有迭代器的使用方法,運行結果為:

三:map的insert方法返回值

這里我們最需要注意的就是map的insert方法返回值:

返回的是一個pair類,第一個參數是iterator,第二個參數是bool。

這是什么意思呢? 這里先說明第二個參數bool:當我們插入一個鍵時,如果當前鍵存在,則說明此鍵已經不能再次插入了,也就是插入失敗,所以測試第二個參數為false;當前鍵不存在,返回true。

第二個參數是iterator,也就是迭代器,經過我們之前的學習(無中生有哈哈),已經知道了iterator本就是指針,這個指針是什么類型的呢?對,是map中存儲數據節點的類型。你已經知道map中存儲的是pair,那么這個迭代器本質也就是pair的指針。

所以為了測試insert方法,我們需要拿iterator來接收它,因為insert返回的是pair,且第一個參數類型是iterator所以要像下面這樣寫:

int main()
{map<int, int> m;int a[] = { 1, 2, 3 };for (auto e : a){m.insert({ e, e });}map<int, int>::iterator it;it = m.insert({ 10, 1 }).first; //insert不能修改!cout << it->first << endl;cout << it->second << endl;return 0;
}

上面代碼中我們插入了一個不存在的鍵,此時insert方法返回的就是{ iterator, true },其中iterator是插入10位置的指針,true代表插入成功。所以結果如下:

之后我們再來嘗試插入相同的值,再次插入10這個鍵:

int main()
{map<int, int> m;int a[] = { 1, 2, 3 };for (auto e : a){m.insert({ e, e });}map<int, int>::iterator it;it = m.insert({ 10, 1 }).first; //insert不能修改!//再次插入10 觀察返回的pair中的值//因為iterator是指針 所以使用重載的->cout << "iterator指向的節點為:" << m.insert({10, 3}).first->first << endl;if (m.insert({ 10, 3 }).second)cout << "插入成功" << endl;elsecout << "插入失敗" << endl;cout << "此時10對應的值為:" << m.insert({10, 3}).first->second << endl;return 0;
}

運行結果為:

可以看到,當10再次插入,已經無法插入,但是返回的iterator會指向10,所以對應的值也無法修改,且insert返回pair第二個參數為false;第一次插入返回10的位置,值為true。

那么我們如何改變對應的值呢?剛才不是說能修改對應的值嗎?

四:map的[ ]的使用

這時我們要修改值不能使用insert,而要是用 [ ] ,這個 [ ] 充當著插入,修改,查找的功能(也就是說底層封裝的insert,更加詳細的解釋可以先下一篇用紅黑樹實現map和set)。

int main()
{map<string, string> dict;dict.insert(make_pair("sort", "排序"));//插入 + 修改dict["left"] = "左邊";//修改dict["left"] = "左邊、剩余";//key不存在->插入 <"insert", "">dict["insert"];//key存在  -> 查找cout << dict["left"] << endl;  //使用[]要謹慎return 0;
}

五:multiset和multimap

這兩個和set、map唯一區別就是他們能存相同的鍵,但使用用法和set、map一樣,不贅述,看文檔。

六:map和set的底層數據結構

前面說了這么多,它們的底層數據結構到底是什么?其實就是紅黑樹!所以不能有相同的鍵。

七:map和set的迭代器

這個很重要,我們已經知道了底層是紅黑樹,那么迭代器起始位置就是中序遍歷的第一個節點。所以當我們使用迭代器遍歷的時候順序是鍵的升序排序。

而剛才說的multi家族,去找一個鍵的時候,返回的是中序遍歷找到第一個節點所在位置。

總結:

我承認這篇寫的很水,因為使用真的很簡單,相信大家也能克服難關。不過大家重點要看insert方法和重載 [ ] ,因為我們接下來就要實現它,大型連續劇之——map和set的實現為您播出!敬請期待!

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

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

相關文章

Mybatis中的一級二級緩存掃盲

思維導圖&#xff1a; MyBatis 提供了一級緩存和二級緩存機制&#xff0c;用于提高數據庫查詢的性能&#xff0c;減少對數據庫的訪問次數。&#xff08;本質上是減少IO次數&#xff09;。 一級緩存 1. 概念 一級緩存也稱為會話緩存&#xff0c;它是基于 SqlSession 的緩存。在同…

uniapp 實現低功耗藍牙連接并讀寫數據實戰指南

在物聯網應用場景中&#xff0c;低功耗藍牙&#xff08;BLE&#xff09;憑借其低能耗、連接便捷的特點&#xff0c;成為設備間數據交互的重要方式。Uniapp 作為一款跨平臺開發框架&#xff0c;提供了豐富的 API 支持&#xff0c;使得在多個端實現低功耗藍牙功能變得輕松高效。本…

OpenSSL應用實踐:嵌入式數據安全實戰指南

文章目錄 OpenSSL應用實踐:嵌入式數據安全實戰指南一、嵌入式安全現狀與OpenSSL適配方案1.1 嵌入式安全挑戰1.2 OpenSSL精簡方案二、開發環境搭建2.1 交叉編譯工具鏈2.2 OpenSSL交叉編譯三、核心功能實現3.1 AES-GCM加密實踐四、實戰項目:安全OTA升級4.1 系統架構4.2 關鍵代碼…

harmonyOS 手機,雙折疊,平板,PC端屏幕適配

由于HarmonyOS設備的屏幕尺寸和分辨率各不相同&#xff0c;開發者需要采取適當的措施來適配不同的屏幕。 1.EntryAbility.ets文件里&#xff1a;onWindowStageCreate方法里判斷設備類型&#xff0c; 如果是pad&#xff0c;需全屏展示&#xff08;按客戶需求來&#xff0c;本次…

跟韓學AiOps系列之2025學MySQL系列_如何在MySQL中開啟和提交事務?!

跟韓學AiOps系列之2025學MySQL系列_如何在MySQL中開啟和提交事務&#xff1f;! 文章目錄 一、事務的基本操作1. 開啟事務2. 執行事務內操作3. 提交事務4. 回滾事務 二、驗證示例&#xff08;適用于 MySQL 5.7&#xff09;步驟 1&#xff1a;準備測試表和數據步驟 2&#xff1a…

Java生成微信小程序碼及小程序短鏈接

使用wx-java-miniapp-spring-boot-starter 生成微信小程序碼及小程序短鏈接 在pom.xml文件中引入依賴 <dependency><groupId>com.github.binarywang</groupId><artifactId>wx-java-miniapp-spring-boot-starter</artifactId><version>4.7…

如何讓通義千問大模型支持結構化輸出?

之前的文章提到通義千問API無法通過with_structured_output/json schema的方式支持結構化輸出&#xff0c;如果就是想使用通義千問大模型做結構化輸出&#xff0c;應該怎么辦呢&#xff1f;有兩種辦法 使用Ollama來運行通義千問大模型 從Ollama博客文章 Structured output 中…

一條 SQL 查詢語句是如何執行的(MySQL)

第一講&#xff1a;一條 SQL 查詢語句是如何執行的 總覽圖示 MySQL 查詢的執行流程可以大致分為以下步驟&#xff08;如圖所示&#xff09;&#xff1a; 連接器&#xff08;Connection&#xff09;查詢緩存&#xff08;Query Cache&#xff0c;MySQL 8.0 已廢棄&#xff09;…

汽車OTA在線升級法規分析

摘要 本文介紹了R156法規即《關于批準車輛的軟件升級和軟件升級管理體系統一規定的法規》、該法規專注于汽車軟件升級功能&#xff0c;并為此提出了一系列具體要求&#xff0c;旨在確保軟件升級流程的安全性、可控性和合規性&#xff0c;從而順應汽車行業智能化、聯網化的發展趨…

Notepad編輯器實現換行符替換

在不同的Note編輯器中&#xff0c;批量把換行替換為空的方法有所不同&#xff0c;以下是常見編輯器的操作方法&#xff1a; Notepad 打開文件后&#xff0c;按CtrlH打開“查找和替換”對話框&#xff0c;在“查找”字段中輸入\r\n&#xff0c;在“替換為”字段中輸入一個空格…

Rust多線程性能優化:打破Arc+鎖的瓶頸,效率提升10倍

一、引言 在 Rust 開發中&#xff0c;多線程編程是提升程序性能的重要手段。Arc&#xff08;原子引用計數&#xff09;和鎖的組合是實現多線程數據共享的常見方式。然而&#xff0c;很多程序員在使用 Arc 和鎖時會遇到性能瓶頸&#xff0c;導致程序運行效率低下。本文將深入剖…

【安裝指南】Centos7 在 Docker 上安裝 RabbitMQ4.0.x

目錄 前置知識:RabbitMQ 的介紹 一、單機安裝 RabbitMQ 4.0.7版本 1.1 在線拉取鏡像 二、延遲插件的安裝 2.1 安裝延遲插件 步驟一:下載延遲插件 步驟二:將延遲插件放到插件目錄 步驟三:啟動延遲插件 步驟四:重啟 RabbitMQ 服務 步驟五:驗收成果 步驟六:手動…

【quantity】5 derive_more庫 2.0 版介紹

derive_more 是一個 Rust 過程宏庫&#xff0c;旨在通過派生宏自動生成常見 trait 的實現&#xff0c;減少樣板代碼。2.0 版本帶來了多項改進和新特性。 主要特性 1. 支持的 Trait 派生 derive_more 2.0 支持派生以下 trait&#xff1a; 基本操作 trait: Display - 格式化顯…

網站備份,網站數據備份的步驟

網站備份&#xff08;尤其是網站數據備份&#xff09;是保障業務連續性、防止數據丟失和應對安全威脅的關鍵措施。以下是系統化的備份步驟和實施建議&#xff0c;涵蓋技術操作、策略規劃及常見問題處理&#xff1a; 一、備份前的準備工作 明確備份范圍 核心數據&#xff1a;…

OpenCV 圖形API(72)圖像與通道拼接函數-----根據指定的方式翻轉圖像(GMat)函數 flip()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 翻轉一個2D矩陣&#xff0c;圍繞垂直軸、水平軸或同時圍繞兩個軸。 該函數以三種不同的方式之一翻轉矩陣&#xff08;行和列的索引是從0開始的&a…

醫生視角下轉錄組學的生物信息學分析

醫生視角下轉錄組學的生物信息學分析 轉錄組學的生物信息學分析是醫生解決臨床與科研問題的有力工具。這里羅列醫學轉錄組學相關的幾個概念&#xff0c;從使用者&#xff08;醫生&#xff09;的角度看待理解相關技術&#xff0c;為后續使用該技術說明臨床和科研問題奠定基礎。…

量子機器學習中的GPU加速實踐:基于CUDA Quantum的混合編程模型探索

引言&#xff1a;量子機器學習的新范式 在量子計算與經典機器學習交叉融合的前沿領域&#xff0c;量子機器學習&#xff08;Quantum Machine Learning, QML&#xff09;正經歷著革命性突破。然而&#xff0c;隨著量子比特規模的增長和算法復雜度的提升&#xff0c;傳統計算架構…

Matplotlib核心課程-2

4.1 數據加載、儲存 4.1.1 從數據文件讀取數據 導入支持庫&#xff1a; import numpy as np from pandas import Series,DataFrame import pandas as pd 從csv文件讀取數據&#xff0c;一般方法&#xff1a; pd.read_csv(../data/ex1.csv,encodinggbk) 從csv文件讀取數據&#…

new和malloc的區別

1 語義層級不同&#xff1a;語言機制 vs. 庫函數 new / new[] (C 關鍵字)malloc / calloc / realloc (C 運行時函數)本質語言級運算符&#xff1b;可被重載庫函數&#xff1b;無法重載作用分配內存 并調用構造函數僅分配原始字節塊&#xff0c;不做初始化&#xff0c;也不調用…

C++11新特性_自動類型推導_auto

在 C11 標準中&#xff0c;auto關鍵字被賦予了全新且強大的功能&#xff0c;它用于自動類型推導&#xff0c;即編譯器能夠根據變量的初始化表達式自動確定其類型。 基本語法 使用auto聲明變量時&#xff0c;只需給出auto關鍵字&#xff0c;后面緊跟變量名&#xff0c;并對其進…