C++【深入 STL--list 之 迭代器與反向迭代器】

? ? ? ? 接前面的手撕list(上)文章,由于本人對于list的了解再一次加深。本文再次對list進行深入的分析與實現。旨在再一次梳理思路,修煉代碼內功。

1、list 基礎架構

? ? ? ? list底層為雙向帶頭循環鏈表,問題是如何來搭建這個list類。可以進行下面的考慮:? ? ? ?

1、list為帶頭雙向循環鏈表,鏈表離不開節點。要能在list內部創建節點。
2、list內部沒有數據時,也應該存在哨兵位頭節點。
3、list內部的數據類型是未知的,需要寫成類模板。
4、list支持迭代器訪問數據,但是由于鏈表的結構來說,普通指針類型的迭代器不能實現++和解引用等基礎訪問操作,這就需要封裝一個迭代器對象。

? ? ? ? 由于鏈表是雙向的,所以節點的成員屬性主要為三個:??

  1. 節點指針類型的_next:指向該節點的下一個節點。
  2. 節點指針類型的_prev:指向該節點的前一個結點。
  3. 未知數據類型的數據_val:鏈表中存放的數據。

? ? ? ? 那么list的成員屬性應該有什么?

  1. 頭節點的指針_head:?作為鏈表的起始點,通過它可以訪問鏈表的第一個元素和最后一個元素。在雙向循環鏈表中,頭節點的_next?指針指向鏈表的第一個有效節點,_prev指針指向鏈表的最后一個有效節點。
  2. 節點的個數_size:記錄鏈表中有效節點的數量,方便快速獲取鏈表的長度,而不需要遍歷整個鏈表來計算。在插入和刪除節點時,需要相應地更新這個計數器。

? ? ? ? 迭代器主要依賴于節點,利用節點才能找到節點當中的數據,并可以通過對運算符的重載實現迭代器本身的基礎操作。故迭代器的成員屬性為節點的指針。

? ? ? ? 由于在list當中要使用到節點當中的所有成員變量,所以這里直接就將節點類寫為struct主要就是在內部的訪問限定符默認為public,迭代器類型也是同樣的道理。

namespace ltq
{template<class T>struct __list_node{__list_node<T>* _prev;__list_node<T>* _next;T _val;};template<class T>struct __list_iterator{typedef __list_node<T> Node;Node* _node;};template<class T>class list{typedef __list_node<T> Node;public:typedef __list_iterator<T> iterator;private:Node* _head;size_t _size;};
}

? ? ? ? 下面需要完善的就是三個類型的構造函數,?首先需要明確關系:list要使用的是節點類和迭代器類,在list類中創建了節點和迭代器對象就會去調用它們自己的構造函數。當然,在外部要是使用到list創建了對象,那么也會調用list自身的構造函數。

		list(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}

? ? ? ? new先開辟空間,然后調用Node的構造函數,由于list的哨兵位節點中可以不用存放數據,所以直接調用Node的默認構造即可。下面就需要完善Node的默認構造。

	template<class T>struct __list_node{__list_node<T>* _prev;__list_node<T>* _next;T _val;__list_node(const T& x = T()):_prev(nullptr),_next(nullptr),_val(x){}};

? ? ? ? 這里的默認構造使用缺省參數,當沒有形參傳過來時就創建T類型的匿名對象對節點中的數據進行初始化。?

2、void push_back(const T& x)

? ? ? ? 雙向帶頭循環鏈表的末尾插入需要找到末尾的節點,再創建新的節點進行鏈接。這里需要更新_size。

		void push_back(const T& x){Node* tail = _head->_prev;Node* newNode = new Node(x);tail->_next = newNode;newNode->_prev = tail;newNode->_next = _head;_head->_prev = newNode;++_size;}

3、迭代器

? ? ? ? 迭代器開始位置返回的是哨兵位頭節點的下一個節點,迭代器的末尾返回的是哨兵位頭節點的指針,這樣設計就能實現左閉右開的區間。

		iterator begin(){return _head->_next;}iterator end(){return _head;}

? ? ? ? ?在前面我故意沒有寫迭代器的構造函數,其實這里就會很明顯的發現,不管是什么類型的迭代器在返回的時候都是傳遞節點的指針。由于單參數的構造函數支持隱式類型的轉換,那么節點的指針就會通過迭代器的構造函數構造出一個迭代器對象并返回,這里需要注意的是,傳值返回會生成臨時對象,臨時對象具有常性。

? ? ? ? 那么,我們現在來實現一下迭代器的構造函數。

	template<class T>struct __list_iterator{typedef __list_node<T> Node;Node* _node;__list_iterator(Node* node):_node(node){}};

3.1、必要的運算符重載

    T& operator*(){return _node->_val;}__list_iterator<T>& operator++(){_node = _node->_next;return *this;}    __list_iterator<T> operator++(int){__list_iterator<T> tmp(*this);_node = _node->_next;return tmp;}bool operator!=(const __list_iterator<T>& it){return _node != it._node;}

? ? ? ? 有了迭代器就支持范圍for了,現在我們來測試一下目前的list是否可用:

3.2、箭頭的重載

? ? ? ? 假如鏈表中存放的是結構體類型的數據,假設結構體為:

struct A
{A(int a1 = 0, int a2 = 0):_a1(a1), _a2(a2){}int _a1;int _a2;
};

? ? ? ? 如果要訪問A內部的數據,此時對迭代器進行解引用是不能訪問到A內部的數據的。此時重載箭頭,通過拿到A對象的地址,使用A的地址來達到訪問內部數據的內容。重載箭頭可以通過解引用再取地址的方式進行實現。

? ? ? ? 當然也可以通過使用對象+.的方式來進行訪問。

4、iterator insert(iterator pos, const T& x)

		iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newNode = new Node(x);newNode->_next = cur;cur->_prev = newNode;newNode->_prev = prev;prev->_next = newNode;++_size;return newNode;}

? ? ? ? ?雖然鏈表的插入不像vector的插入會產生擴容問題而引發迭代器失效,這里返回新插入節點的迭代器主要是方面插入之后的鏈式操作。其次與STL保持一致。

5、iterator erase(iterator pos)

? ? ? ?刪除當前迭代器位置,這里也不像vector,刪除當前位置的數據并不影響后續節點的迭代器,但是當list刪除當前節點時,會進行釋放節點。那么當前節點的迭代器就會懸空,對懸空的迭代器進行操作就會引發錯誤,所以,在刪除之后也會返回下一個節點的迭代器。

		iterator erase(iterator pos){assert(pos != end());Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->_prev = prev;delete pos._node;--_size;return next;}

6、void clear()

? ? ? ? 內部調用erase函數對節點進行清除釋放,但保留頭節點。

		void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}

7、拷貝構造?

? ? ? ? 這里要進行深拷貝,先為新對象創建一個頭結點,再使用范圍for拿出目標鏈表中的每一個數據,直接進行push_back()操作即可。

		list(const list<T>& lt){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;for (auto& e:lt){push_back(e);}}

8、賦值重載

????????直接采用傳值傳參,傳值傳參調用拷貝構造,之后進行對象交換即可。

		void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> tmp){swap(tmp);return *this;}

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

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

相關文章

如何打開vscode系統用戶全局配置的settings.json

&#x1f4cc; settings.json 的作用 settings.json 是 Visual Studio Code&#xff08;VS Code&#xff09; 的用戶配置文件&#xff0c;它存儲了 編輯器的個性化設置&#xff0c;包括界面布局、代碼格式化、擴展插件、快捷鍵等&#xff0c;是用戶全局配置&#xff08;影響所有…

wordpress外貿獨立站常用詢盤軟件

LiveChat LiveChat是一家提供實時聊天軟件的公司&#xff0c;幫助企業通過其平臺與客戶進行即時通訊&#xff0c;提高客戶滿意度和忠誠度。他們的產品允許企業在網站、應用程序或電子郵件等多個渠道與客戶互動&#xff0c;從而提升客戶體驗并促進銷售增長。 LiveChat的軟件特…

STM32 ADC模數轉換器

ADC簡介 ADC&#xff08;Analog-Digital Converter&#xff09;模擬-數字轉換器 ADC可以將引腳上連續變化的模擬電壓轉換為內存中存儲的數字變量&#xff0c;建立模擬電路到數字電路的橋梁 12位逐次逼近型ADC&#xff0c;1us轉換時間 輸入電壓范圍&#xff1a;0~3.3V&#xff0…

(2025,LLM,下一 token 預測,擴散微調,L2D,推理增強,可擴展計算)從大語言模型到擴散微調

Large Language Models to Diffusion Finetuning 目錄 1. 概述 2. 研究背景 3. 方法 3.1 用于 LM 微調的高斯擴散 3.2 架構 4. 主要實驗結果 5. 結論 1. 概述 本文提出了一種新的微調方法——LM to Diffusion (L2D)&#xff0c;旨在賦予預訓練的大語言模型&#xff08;…

DeepSeek 與 ChatGPT 對比分析

一、技術背景與研發團隊 ChatGPT 由 OpenAI 開發&#xff0c;自 2015 年 OpenAI 成立以來&#xff0c;經過多年的技術積累和迭代&#xff0c;從 GPT-1 到 GPT-4o&#xff0c;每一次升級都帶來了技術上的突破。OpenAI 擁有雄厚的技術實力和海量的數據、強大的算力支持&#xff…

學習threejs,pvr格式圖片文件貼圖

&#x1f468;??? 主頁&#xff1a; gis分享者 &#x1f468;??? 感謝各位大佬 點贊&#x1f44d; 收藏? 留言&#x1f4dd; 加關注?! &#x1f468;??? 收錄于專欄&#xff1a;threejs gis工程師 文章目錄 一、&#x1f340;前言1.1 ??PVR貼圖1.2 ??THREE.Mesh…

DeepSeek R1技術報告關鍵解析(8/10):DeepSeek-R1 的“aha 時刻”,AI 自主學習的新突破

1. 什么是 AI 的“aha 時刻”&#xff1f; 在強化學習過程中&#xff0c;AI 的推理能力并不是線性增長的&#xff0c;而是會經歷一些關鍵的“頓悟”時刻&#xff0c;研究人員將其稱為“aha 時刻”。 這是 AI 在訓練過程中突然學會了一種新的推理方式&#xff0c;或者能夠主動…

python:遞歸函數與lambda函數

遞歸函數&#xff1a;1.函數內調用自己 2.有一個出口 1.遞歸 一.有出口時 def sum(num):if num1:return 1return numsum(num-1) asum(3) print(a) #num3 3sum(2) #num2 2sum(1) #num1是返回1 #即3sum(2&#xff09;即32sum(1)即321運行結果 6 二.無出口時 def sum(num)…

ABB 3BSE018741R30 帶插頭連接器的電纜

產品ID:3BSE018741R30 ABB型號名稱:PFTL 101/201/PFCL 201 30米 目錄描述:帶插頭連接器的電纜&#xff0c;30米 ABB型號名稱:PFTL 101/201/PFCL 201 30米 核心信用:0.00 原產國:瑞典波蘭 海關稅則號:85389091 框架尺寸:備件 毛重:5公斤 媒體描述:帶插頭連接器的電纜 最小訂購數…

SpringMVC請求

一、RequestMapping注解 RequestMapping注解的作用是建立請求URL和處理方法之間的對應關系 RequestMapping注解可以作用在方法和類上 1. 作用在類上&#xff1a;第一級的訪問目錄 2. 作用在方法上&#xff1a;第二級的訪問目錄 3. 細節&#xff1a;路徑可以不編寫 / 表示應…

VUE的響應性調試:組件調試鉤子、計算屬性調試、偵聽器調試【僅會在開發模式下工作】

文章目錄 引言I 組件調試鉤子調試事件對象的類型定義鉤子II 計算屬性調試例子回調函數說明III 偵聽器調試引言 VUE的響應性調試的使用場景:確切地知道Vue 的響應性系統正在跟蹤什么,或者是什么導致了組件重新渲染。 I 組件調試鉤子 組件調試鉤子僅會在開發模式下工作 調試…

tkvue 入門,像寫html一樣寫tkinter

介紹 沒有官網&#xff0c;只有例子 安裝 像寫vue 一樣寫tkinter 代碼 pip install tkvue作者博客 修改樣式 import tkvue import tkinter.ttk as ttktkvue.configure_tk(theme"clam")class RootDialog(tkvue.Component):template """ <Top…

藍橋杯試題:排序

一、問題描述 給定 nn 個正整數 a1,a2,…,ana1?,a2?,…,an?&#xff0c;你可以將它們任意排序。現要將這 nn 個數字連接成一排&#xff0c;即令相鄰數字收尾相接&#xff0c;組成一個數。問&#xff0c;這個數最大可以是多少。 輸入格式 第一行輸入一個正整數 nn&#xff…

Java—不可變集合

不可變集合&#xff1a;不可以被修改的集合 創建不可變集合的應用場景 如果某個數據不能被修改&#xff0c;把它防御性地拷貝到不可變集合中是個很好的實踐。當集合對象被不可信的庫調用時&#xff0c;不可變形式是安全的。 簡單理解&#xff1a;不想讓別人修改集合中的內容…

每日Attention學習18——Grouped Attention Gate

模塊出處 [ICLR 25 Submission] [link] UltraLightUNet: Rethinking U-shaped Network with Multi-kernel Lightweight Convolutions for Medical Image Segmentation 模塊名稱 Grouped Attention Gate (GAG) 模塊作用 輕量特征融合 模塊結構 模塊特點 特征融合前使用Group…

響應式編程_04Spring 5 中的響應式編程技術棧_WebFlux 和 Spring Data Reactive

文章目錄 概述響應式Web框架Spring WebFlux響應式數據訪問Spring Data Reactive 概述 https://spring.io/reactive 2017 年&#xff0c;Spring 發布了新版本 Spring 5&#xff0c; Spring 5 引入了很多核心功能&#xff0c;這其中重要的就是全面擁抱了響應式編程的設計思想和實…

C/C++編譯器

C/C 代碼是不可跨平臺的&#xff0c;Windows 和 Unix-like 有著不同的 API&#xff0c;C/C 在不同平臺有著不同編譯器。 MSVC Windows 平臺&#xff0c;MSVC 是 Visual Studio 中自帶的 C/C 編譯器。 GCC Unix-like 平臺&#xff0c;GCC 原名 GNU C Compiler&#xff0c;后…

python gltf生成預覽圖

使用Python生成GLTF模型的預覽圖 隨著3D技術的不斷發展&#xff0c;GLTF&#xff08;GL Transmission Format&#xff09;逐漸成為了Web和移動應用程序中最流行的3D文件格式之一。GLTF文件不僅能以較小的體積存儲復雜的3D模型&#xff0c;還支持動畫、材質、光照和紋理等特性。…

html中的表格屬性以及合并操作

表格用table定義&#xff0c;標簽標題用caption標簽定義&#xff1b;用tr定義表格的若干行&#xff1b;用td定義若干個單元格&#xff1b;&#xff08;當單元格是表頭時&#xff0c;用th標簽定義&#xff09;&#xff08;th標簽會略粗于td標簽&#xff09; table的整體外觀取決…

【JavaScript】《JavaScript高級程序設計 (第4版) 》筆記-Chapter3-語言基礎

三、語言基礎 ECMAScript 的語法很大程度上借鑒了 C 語言和其他類 C 語言&#xff0c;如 Java 和 Perl。ECMAScript 中一切都區分大小寫。無論是變量、函數名還是操作符&#xff0c;都區分大小寫。 所謂標識符&#xff0c;就是變量、函數、屬性或函數參數的名稱。標識符可以由…