C++筆記-list

list即是我們之前學的鏈表,這篇主要還是講解list的底層實現,前面會講一些list區別于前面string和vector的一些接口以及它們的注意事項。

一.list的基本使用

和之前的string,vector一樣,有很多之前見過的一些接口,經過前面兩篇的講解,很多接口不用講解相信大家都會使用,主要就是Operations中的一些接口之前沒有講過,前面主要就是講解這些接口。

這里主要講splice,remove,unique和sort:

1.1splice:
splice的作用是將一個列表中的內容拷貝給另一個鏈表。

可以看出splice有三種傳參的方式,每種方式都會產生不一樣的結果:
1.1.1第一種傳參

第一種傳參中的兩個參數:第一個參數就是從目標位置開始拷貝數據過去,第二個參數代表某個鏈表。

第一種傳參方式就是把第二個參數中鏈表的所有數據都拷貝到第一個參數之前,結果如第二張圖所示,lt1的所有數據都被拷貝到lt2的begin位置之前。

1.1.2第二種傳參

第二種傳參比第一種多了一個參數,意思就是把具體某個位置的值拷貝到目標位置之前,就比如上圖所示的將lt1中的第一個數據拷貝過去。

1.1.3第三種傳參方式

第三種傳參就是把某個范圍的數據拷貝過去,就比如上圖中將lt1中的4到6拷貝過去。

這里可能會有人疑惑:為什么第三個參數直接寫lt1.begin()+3呢?這樣寫不是更簡潔嗎?

這個問題我下面講sort時會講,這里先跳過。

splice還有一種玩法就是可以將自己的數據拷貝到某個位置之前,就比如將最后一個數據拷貝到第一個位置:

這樣就將6放到了第一個位置,這種用法是要比前面的用法更為普遍的。

1.2remove

list中remove作用是將鏈表中所有和你要刪除的值相同的數據一并刪除。

如上圖所示,這里就把所有的2都給刪除了,remove的基本用法就是如此。

1.3unique

unique的作用就是刪除一個有序鏈表中重復的數據。

通過unique就可以把重復的數據給刪掉。

注意:一定要是有序的,如果不是有序的就無法做到刪除重復的數據。

此時鏈表數據不是有序的,unique就沒有發揮作用。

1.4sort

sort的作用相信就不用多說大家都知道,但是在這里我們要思考兩個問題:

1.string和vector都沒有實現sort接口,為什么list要單獨實現?

2.list實現的sort效率怎么樣?

先來解釋第一個問題:
這個問題的答案也能解釋上面splice出現的疑點,這就涉及到迭代器的分類。

迭代器分為三類(移動迭代方式):

1.單向迭代器,如:forword_list/unordered_map...? ?++

2.雙向迭代器,如:list/map...? ?++/--

3.隨機迭代器,如:string/vector/deque.. ++/--/+/-

后面就是它們能夠進行的移動迭代方式,而語法庫中的sort參數是隨機迭代器,list都是雙向迭代器,所以不能使用語法庫中的sort,而上面的splice出現的疑點也是因為雙向迭代器不能+/-,所以不能那樣使用。

中間藍色的單詞的意思就是雙向迭代器。

這是string和vector的隨機迭代器。

這是語法庫中的sort的參數要求,上去就要求隨機迭代器,所以list才需要自己實現。

而迭代器的分類和之前講的權限放大和縮小的概念有些類似,就是如果函數參數要求是雙向迭代器,此時我們傳隨機迭代器也是可以的,相當于權限的縮小,同理單向迭代器也是如此。

雙向迭代器和隨機迭代器就是特殊的單向迭代器。

再來說第二個問題:
我就直接說結論,list自己實現的sort效率不高,比起語法庫中的sort效率低了很多。

不過在數量較少時,效率差不多,但是在數量較大時效率就會低很多,舉個例子:

在數量較大時,把list中的數據拷貝到vector,調用語法庫中的sort,再把數據傳回list的效率都比直接調用list本身的sort高。

二.list的底層實現

2.1list框架的實現

鏈表我們之前在數據結構階段都了解過,鏈表要把整個鏈表和單個結點區分開,所以這里也是同理。

這里定義哨兵位,相信大家都知道底層list其實就是雙向帶頭循環鏈表。

可能有人會疑惑:為什么單個結點要用struct而不用class?

其實我們在實際應用中,想讓別人使用的用class,不想別人訪問的用struct,我們只想讓別人用鏈表整體,而不能直接訪問我一個結點中的變量。

在單個結點類中運用初始化列表進行初始化,這樣在list類中初始化哨兵位時就不需要傳數據,直接創捷一個哨兵位,并讓prev和next都指向自己即可,和之前講鏈表是一樣的。

2.2push_back尾插

思路和之前講鏈表是一樣的,創建一個節點,并更新哨兵位,原尾節點和新建結點的next和prev即可。

2.3iterator迭代器的實現

之前在string中講過迭代器并不就一定是指針,在list中印證了。

為什么在list中要單獨實現iterator迭代器呢?

因為在之前的string和vector中,它們兩個底層都是數組,它們的原生指針就能完成解引用和++等操作,而鏈表我們知道解引用是訪問一個結點,而一個結點不止有數據,還有prev和next,而迭代器我們要求解引用就是直接拿出其中的數據。

包括++等操作,鏈表底層并不是數組,每個結點的地址并不是連續的,所以通過++等操作是不能找到相鄰的結點的。

基于以上兩點,所以在list終究要我們自己實現iterator迭代器,而自定義類型的迭代器其實執行的還是指針的作用,所以成員變量依舊還是單個結點的地址。

其中里面所實現的各種比較我就不過多贅述了,之前都講過,這里主要講解一下為什么多加了一個類型Ref。

因為不僅有iterator,還有const_iterator,兩者的區別無非就是解引用的值能不能修改的問題,但是如果我們沒有多加Ref這個類型,那我們是不是還要寫一個函數重載?

但是從之前學過的函數重載中我們知道,是不能以返回值不同而進行函數重載的,程序會報錯,

那要解決這個問題就只能在單獨寫一個const_iterator類,內容和iterator一樣,除了解引用符號的重載這一個不同而已。

這樣寫代碼就太冗余了,有很多重復代碼,但是我們加一個類型Ref就可以解決這個問題,根據傳過去的參數不同將其分為iterator和const_iterator:

可能有人會疑惑:iterator類不需要實現析構函數嗎?

我們所實現的iterator只是用于解引用和遍歷鏈表而已,不能使用后直接把這個節點給銷毀了,所以不能實現析構函數,相應的也不需要實現拷貝構造函數。

上面的結點類也是一樣,析構操作只需要在list類中實現即可。

另外其中的!=,==等符號的重載是因為現在iterator是自定義類型,不再是原生指針,所以如果要比較自定義類型,就要重載相應的符號。

2.3begin和end

實現了迭代器iterator,接下來就要實現begin和end,也是分為普通和const版本,注意返回值是需要調用iterator類并進行傳參的,頭結點是哨兵位的下個結點,end返回就是哨兵位。

2.4insert

insert實現邏輯和之前一樣,找到目標結點的prev和next,并更新三個結點的next和prev即可。

2.5erase

?

相信現在看到這個返回值大家就知道erase會出現什么問題了,沒錯,還是迭代器失效的問題,所以還是要在erase后更新指針。

需要注意的地方有兩個:

1.目標結點不能是哨兵位

2.刪除當前結點后,要更新指針的位置,指向下個結點

2.6push_front,pop_back和pop_front

這三個包括之前實現的push_back就都可以通過復用insert和erase來實現,要注意的就是尾刪不能直接傳end,要讓end--才是尾結點的位置。

2.7clear

clear的作用就是銷毀除哨兵位之外的所有結點,實現起來也較為容易,遍歷整個鏈表挨個銷毀即可。

2.7拷貝構造函數

實現拷貝構造函數也是為了深拷貝做準備,一樣也要創建哨兵位,不過這和構造函數的代碼一樣,所以其實可以將這段代碼封裝成一個函數也可以,這里因為就幾行代碼所以我就沒整。

下面就是遍歷目標鏈表,把相應的節點push_back進去即可。

2.8=符號重載

以及是需要用到std標準庫中的swap函數進行操作,最后=符號重載復用即可。

我們再看最后一種情況:

當傳進去的參數類型是自定義類型時,我們要訪問其中的數據要用到->符號,但是vector是可以直接用的,因為它用的是原生指針,而list不能使用,因為是自定義類型迭代器,所以在這里我們要自己實現->符號。

和上面的解引用重載一樣,這里我們引進一種類型Ptr,代表要輸出的數據的地址,所以也分為普通和const版本,作用也就和vector原生指針作用是一樣的。

此時就不再會報錯,但是可能有人會覺得很奇怪:不應該是兩個箭頭嗎?

第一個箭頭返回的是指針,應該還有一個箭頭才能指向數據啊。

這個想法沒錯,出現這現象的原因是為了可讀性高,編譯器把另一個箭頭給省略了。

以上就是list的內容。

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

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

相關文章

unityTEngine學習記錄2

上一篇了解了下載項目與外部調用的接口,接下來就繼續學習根據這個框架來加載場景首先打開te官網,進入教程。 了解框架目錄以及功能 首先要了解的就是這個框架的文件結構目錄,知道他都是干啥的,在官網的目錄結構中介紹了其中重要…

邏輯過期怎么設計

設計“邏輯過期”通常用于緩存、令牌管理、數據有效性驗證等場景,其核心是通過業務邏輯判斷數據是否過期(而非單純依賴物理時間)。以下是設計邏輯過期的關鍵思路和實現方案: 1. 核心思想 物理過期:基于固定的時間&…

DAY 47 leetcode 232--棧與隊列.用棧實現隊列

題號232 請你僅使用兩個棧實現先入先出隊列。隊列應當支持一般隊列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; class MyQueue {Stack<Integer> stackIn;Stack<Integer> stackOut;/** Initialize your data structure here. */pu…

邏輯回歸 (Logistic Regression)

文章目錄 邏輯回歸 (Logistic Regression)問題的引出Sigmoid function邏輯回歸的解釋決策邊界 (Decision boundary)邏輯回歸的代價函數機器學習中代價函數的設計1. 代價函數的來源&#xff08;1&#xff09;從概率模型推導而來&#xff08;統計學習視角&#xff09;&#xff08…

關于C語言的模擬物理模型

聲明&#xff1a;本文全部代碼效果基于C語言easyx圖形界面庫。 引言 關于很多游戲和模型的開發&#xff0c;都需要模擬真實的物理模型 比如&#xff1a;基本矢量運動模型&#xff08;位移&#xff0c;速度&#xff0c;加速度&#xff09;&#xff0c;重力模型&#xff0c;碰撞…

C++編譯與鏈接:從源碼到可執行文件的魔法之旅(Visual Studio實踐)

文章目錄 **C++編譯與鏈接:從源碼到可執行文件的魔法之旅(Visual Studio實踐)****一、C++編譯器的工作流程****二、Visual Studio環境配置實戰****三、示例項目:Hello World全流程解析****四、高級技巧與工具鏈****五、總結與參考資料**C++編譯與鏈接:從源碼到可執行文件的…

現代C++的范式演進與工程實踐深度解析(本文序號不知道怎么整的,有點問題)

引言:C++的復興時代 在經歷了"已死語言"的質疑后,現代C++正迎來前所未有的復興。據2024年TIOBE指數顯示,C++以8.33%的占比穩居第三,較2020年上升2.1個百分點。這種復興并非偶然——隨著C++20標準的全面落地和C++23特性的逐步實現,這門已有40年歷史的語言正在系…

通過gird布局實現div的響應式分布排列

目標&#xff1a;實現對于固定寬度的div盒子在頁面中自適應排布&#xff0c;并且最后一行的div盒子可以與前面的盒子對齊。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" con…

WSL2-Ubuntu22.04安裝URSim5.21.3

WSL2-Ubuntu22.04安裝URSim5.21.3 準備安裝啟動 準備 名稱版本WSL2Ubuntu22.04URSim5.21.3VcXsrvNaN WSL2安裝與可視化請見這篇:WSL2-Ubuntu22.04-配置。 安裝 我們是wsl2-ubuntu22.04&#xff0c;所以安裝Linux版本的URSim&#xff0c;下載之前需要注冊一下&#xff0c;即…

產品研發項目管理6大痛點

在產品研發項目管理實踐中&#xff0c;企業普遍面臨六大系統性挑戰&#x1f937;?♀?&#xff0c;直接影響研發效能與戰略目標達成&#x1f514;&#xff0c;具體表現為&#xff1a; ① 產品需求管理不完善&#xff1a;需求與市場脫節&#xff0c;需求不明確、需求變更頻繁…

計算機網絡基礎概論

計算機網絡基礎概論 目錄 一、網絡基本概念 1.1. 網絡 1.2 互聯網 1.3 ip地址 1.3.1 作用 1.3.2 分類 1.4 MAC地址 1.4.1 MAC地址與 IP 地址的關系 1.5 網絡協議 二、網絡分層模型 2.1 物理層 2.2 數據鏈路層 2.3 網絡層 2.4 傳輸層 2.5 會話層 2.6 表示層 2.7…

Windows下導入文件中的環境變量

在Windows批處理腳本&#xff08;.bat&#xff09;中&#xff0c;通過文件獲取并設置環境變量通常涉及逐行讀取文件內容并動態賦值給變量。以下是具體實現方法及示例&#xff1a; 一、從文件讀取變量并設置到環境變量 假設有一個配置文件&#xff08;如env_config.txt&#xf…

WebSocket 實現數據實時推送原理

WebSocket 實現數據實時推送的核心機制在于其全雙工通信能力和持久的連接特性。以下是其工作原理的詳細步驟&#xff1a; 1. 握手階段&#xff08;HTTP 升級協議&#xff09; 客戶端發起請求&#xff1a;通過發送一個帶有特殊頭部的 HTTP 請求&#xff0c;請求協議升級。 GET …

Linux操作系統學習之---進程狀態

目錄 明確進程的概念: Linux下的進程狀態: 虛擬終端的概念: 見一見現象: 用途之一 : 結合指令來監控進程的狀態: 和進程強相關的系統調用函數接口: getpid()和getppid(): fork(): fork函數創建子進程的分流邏輯: 進程之間具有獨立性: 進程中存在的寫時拷貝: 見一見進程狀態…

何小鵬在得意的笑

"小鵬汽車率先邁出了造車新勢力出海一大步" 作者 | 魏強 編輯 | 盧旭成 4月15日&#xff0c;小鵬汽車在香港舉行小鵬全球熱愛之夜和2025首款全球旗艦小鵬X9上市發布會。 當小鵬汽車創始人何小鵬把香車X9交付給香港首批車主的時候&#xff0c;臉上露出經典的笑臉。…

@Autowird 注解與存在多個相同類型對象的解方案

現有一個 Student 類&#xff0c;里面有兩個屬性&#xff0c;分別為 name 和 id&#xff1b;有一個 StuService 類&#xff0c;里面有兩個方法&#xff0c;返回值均為類型為 Student 的對象&#xff1b;還有一個 StuController 類&#xff0c;里面有一個 Student 類型的屬性&am…

黑馬商城項目(三)微服務

一、單體架構 測試高并發軟件 二、微服務 三、SpringCloud 四、微服務拆分 黑馬商城模塊&#xff1a; 服務拆分原則&#xff1a; 拆分服務&#xff1a; 獨立project&#xff1a; maven聚合&#xff1a; 拆分案例&#xff1a; 遠程調用&#xff1a; package com.hmall.cart.…

PyTorch:學習 CIFAR-10 分類

&#x1f50d; 開始你的圖像分類之旅&#xff1a;一步一步學習 CIFAR-10 分類 圖像分類是計算機視覺中最基礎的任務之一&#xff0c;如果你是初學者&#xff0c;那么以 CIFAR-10 為訓練場是一個不錯的選擇。本文一步一步帶你從零開始&#xff0c;學習如何用深度學習模型實現圖…

3.學習筆記--Spring-AOP總結(p39)-Spring事務簡介(P40)-Spring事務角色(P41)-Spring事務屬性(P42)

1.AOP總結&#xff1a;面向切面編程&#xff0c;在不驚動原始基礎上為方法進行功能增強。 2.AOP核心概念&#xff1a; &#xff08;1&#xff09;代理&#xff1a;SpringAOP的核心是采用代理模式 &#xff08;2&#xff09;連接點&#xff1a;在SpringAOP中&#xff0c;理解為任…

數據庫-day06

一、實驗名稱和性質 分類查詢 驗證 綜合 設計 二、實驗目的 1&#xff0e;掌握數據查詢的Group by &#xff1b; 2&#xff0e; 掌握聚集函數的使用方法。 三、實驗的軟硬件環境要求 硬件環境要求&#xff1a; PC機(單機) 使用的軟件名稱、版本號以及模塊&#xff1a; …