《map和set的使用介紹》

引言:

上次我們學習了第一個高階數據結構—二叉搜索樹,趁熱打鐵,今天我們就再來學習兩個數據結構—mapset

一:序列式容器和關聯式容器

前面我們已經接觸過STL中的部分容器如:stringvectorlistdequearrayforward_list等,這些容器統稱為序列式容器,因為邏輯結構為線性序列的數據結構,兩個位置存儲的值之間一般沒有緊密的關聯關系,比如交換一下,他依舊是序列式容器。順序容器中的元素是按他們在容器中的存儲位置來順序保存和訪問的。
關聯式容器也是用來存儲數據的,與序列式容器不同的是,關聯式容器邏輯結構通常是非線性結構,兩個位置有緊密的關聯關系,交換一下,他的存儲結構就被破壞了。順序容器中的元素是按關鍵字來保存和訪問的。關聯式容器map/set系列和unordered_map/unordered_set系列。
本章節我們要學習的mapset底層是紅黑樹紅黑樹是一顆平衡二叉搜索樹setkey搜索場景的結構,mapkey/value搜索場景的結構。

二:set系列的使用

1. setmultiset 的參考文檔:

set / multiset的參考文檔:

2. set類的介紹:

set的聲明如下,T就是set底層關鍵字的類型

  1. set默認要求T?持小于比較,如果不支持或者想按自己的需求走可以自行實現仿函數傳給第二個模版參數。
    2.·set底層存儲數據的內存是從空間配置器申請的,如果需要可以自己實現內存池,傳給第三個參數。
  2. 一般情況下,我們都不需要傳后兩個模版參數。
  3. set底層是用紅黑樹實現,增刪查效率是O(logN) ,迭代器遍歷是走的搜索樹的中序,所以是有序的。
  4. 前面部分我們已經學習了vector/list等容器的使用,STL容器接口設計,高度相似,所以這里我們就不再一個接口一個接口的介紹,只是挑比較重要的接口進行介紹。
    template < class T,
    class Compare = less<T>,
    class Alloc = allocator<T> > class set;

3. set的構造和迭代器

(1)構造函數:

介紹文檔:
set的構造我們關注以下幾個接口即可。
set支持正向和反向迭代遍歷,遍歷默認按升序順序,因為底層是二叉搜索樹,迭代器遍歷走的中序,支持迭代器就意味著支持范圍for,setiteratorconst_iterator都不支持迭代器修改數據,修改關鍵字數據,破壞了底層搜索樹的結構。

代碼演示:

(1) 無參默認構造
explicit set (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
(2) 迭代器區間構造
template <class InputIterator>
set (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());
(3) 拷貝構造
set (const set& x);
(5) initializer 列表構造
set (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());

(2) 迭代器:

begin():返回指向第一個數據的迭代器。
end():返回最后一個數據下一個位置的迭代器。
cbegin():返回最后一個元素的迭代器。
cend():返回第一個數據的前一個位置的迭代器。
set的迭代器是一個雙向迭代器
iterator -> a bidirectional iterator to const value_type

  1. 正向迭代器
    iterator begin();
    iterator end();
  2. 反向迭代器
    reverse_iterator rbegin();
    reverse_iterator rend();

4. set的增刪查:

(1)插入:

insert函數

代碼演示:

在這里插入圖片描述

(2)查找:
  1. find(): 查找val,返回val所在的迭代器,沒有找到返回end()。
  2. count():查找val,返回Val的個數。
代碼演示:

在這里插入圖片描述

(3)刪除:
  1. iterator erase (const_iterator position): 刪除一個迭代器位置的值。
  2. size_type erase (const value_type& val):刪除val,不存在返回0,存在返回1。
  3. iterator erase (const_iterator first, const_iterator last):刪除一段迭代器區間的值。
代碼演示:

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

(4) lower_boundupper_bound
  1. lower_bound:返回大于等val位置的迭代器。
  2. upper_bound:返回大于val位置的迭代器。

注:因此借助這兩個接口就可以得到一段左閉右開的區間。

代碼演示:

在這里插入圖片描述

5. insert 和迭代器遍歷使用樣例:

在這里插入圖片描述

在這里插入圖片描述
注:這里的范圍for我們寫成了引用的形式,是為了提高效率。

6. find和erase的使用樣例:

在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
注:這是我們借助count間接實現的查找。

算法庫中的findset中的find對比:

在這里插入圖片描述

7. multisetset的差異

multisetset的使用基本完全類似,主要區別點在于multiset支持值冗余,那么
insert/find/count/erase都圍繞著支持值冗余有所差異,具體參看下面的樣例代碼理解:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

8. 牛刀小試:

(1)題目描述:

在這里插入圖片描述

代碼解決:
方法一-暴力匹配:

先將兩個數組通過set來去重,之后遍歷其中一個來借助count來判斷是否有交集。
在這里插入圖片描述

方法二-雙指針:

該解法的思路是在去重+升序排序后的基礎上來遍歷兩個容器
定義兩個指針p1p2分別遍歷兩個set

  1. 小的那個++
  2. 相等的話就存下來,p1++p2++
  3. 當其中一個容器遍歷完之后,就結束、
    為什么這樣是對的呢?
    因為如果其中一個小的話,由于數據是升序的,因此當前必不可能為交集,若存在交集的話只可能在它之后,因此往后走。
    在這里插入圖片描述
題目傳送門:349. 兩個數組的交集

三: map系列的使用

1. mapmultimap的介紹文檔:

map 和multimap的介紹文檔:

2. map類的介紹:

map的聲明如下,Key就是map底層關鍵字的類型,Tmap底層value的類型,map默認要求Key支持小于比較,如果不支持或者需要的話可以自行實現仿函數傳給第二個模版參數,map底層存儲數據的內存是從空間配置器申請的。一般情況下,我們都不需要傳后兩個模版參數。map底層是用紅黑樹實現,增刪查改效率是,迭代器遍歷是走的中序,所以是按key有序順序遍歷的。O(logN) ,迭代器遍歷是走的中序,所以是按key有序順序遍歷的。

template < class Key,
class T,
class Compare = less<Key>,
class Alloc = allocator<pair<const Key,T> > > class map;

3. pair類型介紹:

map底層的紅黑樹節點中的數據,使用pair<Key,T>存儲鍵值對數據。
pair:
typedef pair<const Key, T> value_type;
template <class T1, class T2>
struct pair
{typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair(): first(T1()), second(T2())
{}
pair(const T1& a, const T2& b): first(a), second(b)
{}
template<class U, class V>
pair (const pair<U,V>& pr): first(pr.first), second(pr.second)
{}
};
template <class T1,class T2>
inline pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair<T1,T2>(x,y) );
}
上面是pair的底層結構,實質上就是一個類模版的結構體。先這么理解即可。

思考:為什么map里面要用pair呢?

這是因為map里面是存儲兩個數據,如果你單獨分開存兩個數據的話,是沒辦法解引用的,因為解引用只能拿到一個數據,用pair的話,解引用會拿到pair類型的數據,之后可以通過pair類型的性質來拿到兩個數據。

4. map的構造和迭代器:

(1) 構造函數:

map的構造函數介紹文檔:
map的構造我們關注以下幾個接口即可。
map的支持正向和反向迭代遍歷,遍歷默認按key的升序順序,因為底層是二叉搜索樹,迭代器遍歷走的中序;支持迭代器就意味著支持范圍for,map支持修改value數據,不支持修改key數據,修改關鍵字數據,破壞了底層搜索樹的結構。

(1) 無參默認構造
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
(2) 迭代器區間構造
template <class InputIterator>
map (InputIterator first, InputIterator last,
const key_compare& comp = key_compare(),
const allocator_type& = allocator_type());
(3) 拷貝構造
map (const map& x);
(4) initializer 列表構造
map (initializer_list<value_type> il,

(2)迭代器:
  1. begin():返回指向第一個數據的迭代器。
  2. end():返回最后一個數據下一個位置的迭代器。
  3. cbegin():返回最后一個元素的迭代器。
  4. cend():返回第一個數據的前一個位置的迭代器。

map的迭代器也是?個雙向迭代器
iterator -> a bidirectional iterator to const value_type

  1. 正向迭代器
    iterator begin();
    iterator end();
  2. 反向迭代器
    reverse_iterator rbegin();
    reverse_iterator rend();

5. map 的增刪查

(1)插入:

insert介紹文檔:

代碼演示:

在這里插入圖片描述

(2)查找:
  1. find():查找k,返回k所在的迭代器,沒有找到返回end()。
  2. count():查找k,返回k的個數。
代碼演示:

在這里插入圖片描述

(3) 刪除:
  1. iterator erase (const_iterator position):刪除?個迭代器位置的值。
  2. size_type erase (const key_type& k):刪除k,k存在返回0,存在返回1。
  3. iterator erase (const_iterator first, const_iterator last:刪除一段迭代器區間的值。
(4) lower_boundupper_bound
  1. lower_bound:返回大于等k位置的迭代器。
  2. upper_bound:返回大于k位置的迭代器。
代碼演示:

在這里插入圖片描述
注:這里默認是按照第一個關鍵字來比較的。

6. map的數據修改

前面提到map支持修改mapped_type數據,不支持持修改key數據,修改關鍵字數據,破壞了底層搜索樹的結構。
map第一個支持修改的方式是通過迭代器,迭代器遍歷時或者find返回key所在的iterator修改,map還有一個非常重要的修改接口operator[],但是operator[]不僅僅支持修改,還支持插入數據和查找數據,所以他是一個多功能復合接口
需要注意從內部實現角度,map這里把我們傳統說的value值,給的是T類型
typedefmapped_type。而value_type是紅黑樹結點中存儲的pair鍵值對值。日常使用我們還是習慣將這里的T映射值叫做value

7.map的迭代器和[]功能樣例:

在這里插入圖片描述
其實這里的代碼還可以這樣寫:
在這里插入圖片描述
這樣寫的話,對于已經存在的數據的修改大家都沒問題,但是一些同學可能會疑惑數據第一次出現的時候是怎么統計的呢?
其實在數據第一次出現的時候,會先將這個數據插入,這時候第二個參數就是一個默認值0,之后在進行修改。

operator[] 底層解釋:

要搞清楚operator[]的底層就需要先從insert入手。
在這里插入圖片描述
可以看到insert的第一個實現形式的返回值是pair類型,由迭代器和bool值組成。
在這里插入圖片描述

我們再來看第一種形式的返回值的解讀:
這里說的是當該數據是第一次插入的話,就會返回指向這個新插入數據的迭代器,否則就會返回map中指向該數據的迭代器,第二個bool值,如果數據是第一次插入的新數據就會返回true,否則就是返回false
因此operator[]其實大概就是這樣實現的:

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

8. multimapmap的差異

multimapmap的使用基本完全類似,主要區別點在于multimap支持關鍵值key冗余,那么insert/find/count/erase都圍繞著支持關鍵值key冗余有所差異,這里跟setmultiset完全?樣,比如find時,有多個key,返回中序第一個。其次就是multimap不支持[],因為支持key冗余,[]就只能支持插入了,不能支持修改。

9. 牛刀小試:

(1)題目描述:

在這里插入圖片描述

(2)思路分析:

首先從題目就能知道這是一個經典的TopK問題,但是與之前不同的是這個是雙元素的,因此我們就得用pair來存儲,所以我們的思路就是先用map來統計各單詞的出現次數,再創建小根堆來維護前k個出現次數最多的單詞,之后用vector來存儲結果,但由于我們創建的是小根堆,因此在返回結果的時候還需要進行逆置。

(3)代碼實現:

在這里插入圖片描述

(4)題目傳送門:

692. 前K個高頻單詞

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

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

相關文章

PostgreSQL(二十六)分區表管理

目錄 一、分區表特點 1、概念&#xff1a; 2、好處&#xff1a; 3、特點&#xff1a; 二、范圍分區介紹 1、簡介 2、范圍分區實驗&#xff1a; 三、list分區介紹 1、簡介 2、list分區表實驗 四、hash分區介紹 1、簡介 2、hash分區表實驗 五、混合分區介紹 1、簡…

概率論中的生日問題,違背直覺?如何計算? 以及從人性金融的角度分析如何違背直覺的?

一、生日問題的概率計算&#xff1a;為何23人就有50%概率撞生日&#xff1f; 1. 問題背景與直覺矛盾 生日問題指&#xff1a;在n個人中&#xff0c;至少有兩人生日相同的概率超過50%時&#xff0c;n的最小值是多少&#xff1f; 直覺判斷&#xff1a;因一年有365天&#xff0c…

Qt for WebAssembly官方說明文檔

鏈接 Qt for WebAssembly | Qt 5.15

前端自主實現將vue頁面轉為pdf文件下載

1.vue 轉 PDF 在 Vue 項目中將 HTML 頁面轉換為 PDF 文件是一個常見需求&#xff0c;特別是在需要生成報告或打印頁面時。本文將介紹如何使用 html2canvas 和 jspdf 庫實現這一功能。 2.安裝依賴 首先&#xff0c;我們需要安裝兩個庫&#xff1a;html2canvas 和 jspdf 。可以…

TCP 堅持定時器詳解:原理、配置與最佳實踐?

一、TCP 堅持定時器基礎原理 1.1 堅持定時器的設計目的 TCP 堅持定時器 (TCP Persist Timer) 是 TCP 協議中用于處理接收窗口為零情況的重要機制&#xff0c;其核心設計目的是防止 TCP 連接在窗口更新 ACK 丟失時陷入死鎖狀態。當 TCP 連接的接收方通告一個窗口大小為 0 的 A…

大廠測開實習和小廠開發實習怎么選

先說選擇&#xff0c;這個可以百分百確定選大廠&#xff0c;title很重要。 要想弄清楚那個選擇對自己最有利&#xff0c;可以思考下實習的意義是什么&#xff1f; 實習無非就是給簡歷加分&#xff0c;拿到好offer&#xff0c;高薪offer。 那這就需要思考&#xff0c;簡歷怎么讓…

Unity中的urp和普通的標準渲染管線區別在哪

Unity中的URP&#xff08;Universal Render Pipeline&#xff09;與內置標準渲染管線&#xff08;Built-in Render Pipeline&#xff09;的區別深刻反映了Unity渲染技術的演進方向。以下從架構、性能、功能、工作流等多個維度進行深度分析&#xff1a; 1. 底層架構與設計哲學 標…

Vscode 編寫Markdown支持 plantuml書寫

1&#xff1a; 下載PlantUml 插件&#xff1a; 2&#xff1a; 安裝java https://www.oracle.com/java/technologies/downloads/ 3&#xff1a; 安裝Graphviz https://graphviz.org/download/ 4&#xff1a; 下載plantuml.jar https://plantuml.com/zh/download 5&…

設計模式(C++/Qt)-工廠模式

在軟件開發中&#xff0c;對象創建是基礎但關鍵的任務——工廠模式提供了一種優雅的解決方案&#xff0c;讓您的代碼擺脫硬編碼的依賴關系 一、為什么需要工廠模式&#xff1f; 在C/Qt開發中&#xff0c;我們經常面臨這樣的困境&#xff1a; 對象創建邏輯分散在代碼各處新增…

Pydantic 模型

本文將詳細介紹 Pydantic 模型 和 BaseModel 的核心概念&#xff0c;并通過實際代碼示例如何從零開始編寫自己的 Pydantic 模型。 1. Pydantic 是什么&#xff1f; Pydantic 是一個 Python 庫&#xff0c;主要用于&#xff1a; 數據驗證&#xff1a;確保輸入數據符合預期的類…

【Unity智能模型系列】MediaPipeUnityPlugin 實現人臉數據獲取

目錄 一、MediaPipeUnity 簡介 二、MediaPipeUnity 的核心組成 1. Graph 構建系統 2. 解決方案類(Solution) 3. 解釋注釋Annotation 系統 三、MediaPipeUnity 的典型使用流程 四、典型示例解析 1、案例 Face Detection圖形人臉檢測 2、案例 Face Detection圖形人臉檢…

iOS App 上架步驟解析:適合資源有限團隊的上架流程與注意事項

對于不少創業型或初創階段的開發團隊來說&#xff0c;人員配置緊湊、設備有限是常態。在這種背景下&#xff0c;完成一次合規、高效的iOS應用發布往往不是技術難點&#xff0c;而是流程協同與資源調配的問題。 我們是一支5人團隊&#xff0c;開發一款社交類工具型App&#xff…

Redis雪崩、穿透、擊穿原理及解決方案

以下是 Redis 緩存穿透、擊穿與雪崩的原理及解決方案的深度解析&#xff0c;結合工業級實踐整理&#xff1a; &#x1f50d; ?一、問題原理與區別? ?問題類型??觸發條件??核心特征??危害??緩存穿透?查詢?不存在的數據?繞過緩存直擊數據庫&#xff0c;導致無效查…

DFX 動態重構的概念和實現

DFX 動態重構的概念和實現 背景介紹 本文內容當前僅限于XILINX或者和XILINX具有相同結構的FPGA器件。 FPGA 技術提供了在現場進行編程和重新編程的靈活性&#xff0c;而無需通過重新制造流程來實現設計修改。動態功能交換&#xff08;Dynamic Function eXchange, DFX&#x…

hutool 導出數據報錯:org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException

Excel 導出報錯 org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException: Fail to save: an error occurs while saving the package : The part /docProps/core.xml failed to be saved in the stream with marshaller org.apache.poi.openxml4j.opc.internal.marsh…

【學習】win 本地部署qwen3

這里寫自定義目錄標題 環境搭建下載Ollama安裝olama修改模型下載位置&#xff08;可以不設置&#xff09;通過ollama下載/啟動模型常用命令其他 環境搭建 下載Ollama 安裝olama 默認安裝位置是c盤 安裝到指定位置使用以下命令 OllamaSetup.exe /DIR"d:\Ollama"修改…

python的__init__.py

在此之前先確認一個概念是否弄清 模塊命名空間 1. 目錄結構 假設你有以下結構&#xff1a; testpkg/__init__.pyfool.pymaybe.py內容如下&#xff1a; fool.py # testpkg/fool.py class Fool:passmaybe.py # testpkg/maybe.py class Maybe:pass__init__.py &#xff08…

四核 A53+工業級存儲:移遠 SC200L 與 pSLC SD NAND 如何重構 T-BOX 性能邊界?

博客目錄 一、移遠 SC200L&#xff1a;T-BOX 的 “智慧大腦”二、米客方德 MKDN064GIL-ZA T-BOX&#xff1a;數據安全的堅固堡壘三、深度協同&#xff1a;拓展 T-BOX 應用邊界 在車聯網浪潮席卷而來的當下&#xff0c;T-BOX 作為汽車與外界交互的核心樞紐&#xff0c;其性能優劣…

JavaEE-統一功能處理

攔截器 實現強制登錄的功能, 后端程序根據Session來判斷??是否登錄, 但是實現?法是?較?煩的 需要修改每個接?的處理邏輯 需要修改每個接?的返回結果 接?定義修改, 前端代碼也需要跟著修改 有沒有更簡單的辦法, 統?攔截所有的請求, 并進?Session校驗呢, 這?我們學…

vscode運行c++文件和插件的方法

1.運行c文件全過程 VSCode運行C全教程-CSDN博客 按照以上的操作即可完成正常的配置流程。但是在運行我的文件時&#xff0c;總是出現終端和輸出混亂的情況&#xff0c;我想要在終端中進行輸入輸出的話&#xff0c;需要加一個改動&#xff1a;設置--輸入Run In Terminal--勾選…