C++:STL中list的使用和模擬實現

C++中的list是標準模板庫(STL)提供的雙向鏈表容器,支持高效的元素插入和刪除操作。在上一篇中講解了vector的使用和模擬實現,vector是具有連續的空間,迭代器是可以隨機的,而list卻于vector不同,list是帶頭雙向循環鏈表,迭代器是雙向的,空間并不是連續的,所以在底層實現上比vector復雜一點。與vector?不同,list?在任意位置插入或刪除元素的時間復雜度為 O(1),但隨機訪問的性能較差(時間復雜度為 O(n))。

目錄

list的介紹

?list的使用

list的構造

list的插入和刪除?

list訪問元素?

list的大小和容量?

list迭代器的使用?

list的模擬實現?

迭代器中的函數?


list的介紹

1. list是可以在常數范圍內在任意位置進行插入和刪除的序列式容器,并且該容器可以前后雙向迭代。

2. list的底層是雙向鏈表結構,雙向鏈表中每個元素存儲在互不相關的獨立節點中,在節點中通過指針指向 其前一個元素和后一個元素。

3. list與forward_list非常相似:最主要的不同在于forward_list是單鏈表,只能朝前迭代,已讓其更簡單高 效。

4. 與其他的序列式容器相比(array,vector,deque),list通常在任意位置進行插入、移除元素的執行效率 更好。

5. 與其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的隨機訪問,比如:要訪問list 的第6個元素,必須從已知的位置(比如頭部或者尾部)迭代到該位置,在這段位置上迭代需要線性的時間 開銷;list還需要一些額外的空間,以保存每個節點的相關聯信息(對于存儲類型較小元素的大list來說這 可能是一個重要的因素)

?list的使用

list是帶頭雙向循環鏈表,如果迭代器要進行++、--、*(解引用)等操作是否跟vector一樣呢,當然不是,兩者的結構不同注定迭代器也不一樣,但是為了方便大家使用將list的迭代器進行了封裝,依然是lis<T>iterator來進行各種操作,list的空間不是連續的,所以在實現++、--、*等操作就需要進行運算符重載來定義該運算符的行為,在使用上迭代器vector和list沒什么兩樣,但是在底層卻大大不同。

list的構造

list (size_type n, const value_type& val = value_type()) //構造的list中包含n個值為val的元素list() //構造空的listlist (InputIterator ?rst, InputIterator last) //用[?rst, last)區間中的元素構造list

使用list需要包含頭文件。初始化的方式包括默認構造、指定大小初始化、通過迭代器范圍初始化等。?

示例:

#include <list>
#include <iostream>
using namespace std;int main() {list<int> l1; // 空列表list<int> l2(5, 10); // 包含5個值為10的元素list<int> l3 = {1, 2, 3, 4, 5}; // 列表初始化return 0;
}

list的插入和刪除?

push_back(val):在末尾插入元素。

push_front(val):在頭部插入元素。

pop_back(val):刪除末尾元素。

pop_front(val):刪除頭部元素。

insert(pos,val):在指定位置插入元素。

erase(pos):在指定位置刪除元素。

示例:?

std::list<int> l = {1, 2, 3};
l.push_back(4); // {1, 2, 3, 4}
l.push_front(0); // {0, 1, 2, 3, 4}
l.pop_back(); // {0, 1, 2, 3}
l.pop_front(); // {1, 2, 3}
auto it = l.begin();
it++;
l.insert(it, 10); // {1, 10, 2, 3}
l.erase(it); // {1, 10, 3}

list訪問元素?

front():返回第一個元素。

back():返回最后一個元素。

由于list的結構不支持operator【】或者at()隨機訪問。?

示例:

std::list<int> l = {1, 2, 3};
std::cout << l.front() << std::endl; // 輸出1
std::cout << l.back() << std::endl; // 輸出3

list的大小和容量?

在vector中擴容是很常見的,擴容之后需要拷貝,而在list中就不存在這樣的問題,當插入一個值就new一個節點再鏈接起來,不需要拷貝,按需申請。

size():返回元素數量。

empty():判斷是否為空。

示例:

std::list<int> l = {1, 2, 3};
std::cout << l.size() << std::endl; // 輸出3
std::cout << l.empty() << std::endl; // 輸出0(false)

list 提供了一些特有操作:

sort():排序(默認升序,可自定義比較函數)。
merge(other_list):合并兩個有序列表。
splice(pos, other_list):將另一個列表的元素移動到指定位置。
unique():刪除連續重復元素。

示例:?

std::list<int> l1 = {3, 1, 2};
std::list<int> l2 = {5, 4, 6};
l1.sort(); // {1, 2, 3}
l2.sort(); // {4, 5, 6}
l1.merge(l2); // l1: {1, 2, 3, 4, 5, 6}, l2為空
l1.unique(); // 刪除重復元素

list迭代器的使用?

?list提供雙向迭代器,有begin()、end()、rbegin()、和rend()。

std::list<int> l = {1, 2, 3};
for (auto it = l.begin(); it != l.end(); it++) {std::cout << *it << " ";
}
// 輸出:1 2 3

想知道更多list的更多接口可以看這里:https://legacy.cplusplus.com/reference/list/list/?kw=list?

list的模擬實現?

在實現list之前我們需要知道list的結構是帶頭雙向循環鏈表,迭代器也是和vector不一樣,需要去實現封裝迭代器,list迭代器需要和vector的迭代器有一樣的功能,所以需要定義一個結構體迭代器在該結構體中去實現迭代器的各種行為。而迭代器還有const修飾的迭代器,所以模版參數可不止一個,需要注意的是const修飾的迭代器本身是可以進行++等操作的,而迭代器指向的內容是只讀不可寫的。只要對迭代器的實現完善好接下來的工作就十分好做,模擬實現list的重難點就在于如何去實現迭代器。

代碼展示:

template<class T>//結點struct list_node {list_node<T>* _next;list_node<T>* _prev;T _val;list_node(const T& val = T()):_next(nullptr),_prev(nullptr),_val(val){}};template<class T, class Ref, class ptr>//迭代器struct _list_iterator {typedef list_node<T> Node;//節點類型typedef _list_iterator<T, Ref, ptr> Self;Node* _node; \\指向當前鏈表節點的指針\\構造函數:初始化迭代器指向特定節點_list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_val;}ptr operator->(){return &_node->_val;}Self& operator++()//前置{_node = _node->_next;return *this;}Self& operator++(int)//后置{_list_iterator<T> tmp(*this);_node = _node->_next;return tmp;}Self& operator--()//前置{_node = _node->_prev;return *this;}Self& operator--(int)//后置{Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};

模版參數:

T:鏈表元素的類型(如:int、string),與節點定義中的T一致。

Ref:引用類型,用于operator*的返回類型。通常為T&(非const迭代器)或者const T& (const迭代器)

ptr:指針類型,用于operator->的返回類型。通常為T*(非const)或者const T*(const)

對于內部typedef:

typedef list_node<T> Node; 定義節點類型。

typedef _list_iterator<T, Ref, ptr> Self; 定義自身類型,方便使用。

迭代器中的函數?

Ref operator*():解引用運算符,返回當前節點值的引用。

作用:允許*it的語法訪問元素值。例如it是迭代器,*it就可以獲取節點儲存的值。

ptr operator->():成員訪問運算符,返回指向節點值的指針。

作用:支持it->member語法。例如,如果T是結構體類型,it->member訪問其成員。

Self& operator++()(前置遞增):移動到下一個節點,并返回更新后的迭代器引用。?

作用:用于++it語法。效率高,因為直接修改并返回自身。?

Self operator++(int)(后置遞增):返回當前迭代器的副本,然后移動到下一個節點。

作用:用于it++語法。參數int是占位符,用于區分前置和后置版本。注意返回類型是Self(值類型),不是引用,因為返回的是臨時副本。

Self& operator--()(前置遞減):移動到前一個節點,并返回更新后的迭代器引用。

作用:用于--it語法。正確利用了雙向鏈表的_prev指針?

Self operator--(int)(后置遞減):返回當前迭代器的副本,然后移動到前一個節點。

作用:用于it--語法。

bool operator!=(const Self& it):檢查兩個迭代器是否指向不同節點。

作用:用于it1 != it2語法。例如,在循環中判斷是否到達結尾。

此迭代器實現是STL風格雙向鏈表的核心部分:它封裝了節點指針,提供統一的元素訪問和遍歷接口。通過模板參數,優雅地支持const和非const迭代器。運算符重載使迭代器用法類似原生指針(如*it、it->、++it)。

list代碼:

template<class T>//雙向循環鏈表class list {typedef list_node<T> Node;public:typedef _list_iterator<T,T&,T*> iterator;typedef _list_iterator<T,const T&,const T*> const_iterator;//const T* ptr //const 修飾的是指針指向的內容,不能修改//T* const ptr // const 修飾的是指針,指針不能修改list(){head = new Node;head->_next = head;head->_prev = head;n = 0;}list(const list<T>& lt){head = new Node;head->_next = head;head->_prev = head;n = 0;for (auto& e : lt){push_back(e);}}~list(){clear();}iterator begin(){return head->_next;}iterator end(){return head;}const_iterator begin() const{return const_iterator(head->_next);}const_iterator end() const{return const_iterator(head);}void push_back(const T& x){Node* tail = head->_prev;Node* newnode = new Node(x);tail->_next = newnode;newnode->_prev = tail;head->_prev = newnode;newnode->_next = head;n++;//insert(--end(),x);}void pop_back(){erase(--end());}void push_front(const T* x){insert(begin(), x);}void pop_front(){erase(begin());}iterator insert(iterator pos, const T& x){Node* newnode = new Node(x);Node* cur = pos._node->_prev;newnode->_next = cur->_next;newnode->_prev = cur;cur->_next->_prev = newnode;cur->_next = newnode;n++;return newnode;}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node->_next;Node* prev = pos._node->_prev;cur->_prev = prev;prev->_next = cur;/*pos._node->_next = pos._node->_prev = nullptr;*/delete pos._node;n--;return cur;}void swap(list<T>& lt){std::swap(head, lt.head);std::swap(n, lt.n);}list<T>& operator=(list<T> lt){swap(lt);return *this;}void clear(){/*Node* cur = head->_next;while (cur != head){Node* next = cur->_next;delete cur;cur = next;}head->_next = head;head->_prev = head;n = 0;*/iterator it = begin();while (it != end()){it = erase(it);}}size_t size(){return n;}private:Node* head;size_t n;};

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

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

相關文章

【編號58-61】我國四大高原矢量示意圖shp數據

今天分享的是&#xff1a;中國四大高原&#xff0c;分別是青藏高原、內蒙古高原、黃土高原、云貴高原。青藏高原位置與范圍&#xff1a;位于中國西南部&#xff0c;包括西藏、青海的全部&#xff0c;川西高原及滇西北高原等部分地區。它的邊界&#xff0c;向東是橫斷山脈&#…

【AI落地應用實戰】利用 Amazon Bedrock Claude3 打造個性化 AI Character 應用

目錄一、引言&#xff1a;AI Character應用的市場前景與技術基礎二、技術架構設計2.1、整體方案概述2.2、核心組件介紹2.3、部署架構圖三、系統部署方案3.1、方案總述3.2、實踐流程1??. Bedrock 配置2??. 安裝 SillyTavern3??. 配置 SillyTavern 使用 Claude3 模型4??.…

Java常用日志框架介紹

Java提供了很多第三方的日志框架可供使用&#xff0c;按照現在的設計理念&#xff0c;一般把日志框架分成門面(Facade)部分和具體實現(Implementation)部分&#xff0c;門面(Facade)提供了抽象的api規范&#xff0c;實現(Implementation)負責實現api完成具體的日志記錄功能。開…

飛書 —— 多維表格 —— AI生成

1.添加關聯賬號&#xff1a; 2.獲取密鑰 ARK_API_KEY 進入火山引擎服務頁面&#xff1a;https://console.volcengine.com/ark/region:arkcn-beijing/model/detail?Iddeepseek-r1 先進入推理模型 > 快捷API接入 再去在線推理中創建推理接入點 點擊新創建好的接入點的API調…

我的世界模組開發教程——資源(1)

下面我們來研究一下ResourceLocation,每次開啟游戲時都會報這個錯誤:“ResourceLocation 中的 ResourceLocation(String) 已過時, 且標記為待刪除”,下面我們來詳細的研究一下這個類 ResourceLocation ResourceLocation 是 Minecraft 中用于唯一標識游戲資源的核心類(如方…

我從 Web2 轉型到 Web3 的 9 條經驗總結

作者&#xff1a;Forte Group 高級區塊鏈工程師 Yurii Kovalchuk原文&#xff1a;https://cryptoslate.com/why-i-left-web2-for-web3-and-why-you-might-too/三年前&#xff0c;我做出了一個徹底改變職業軌跡的決定&#xff1a;離開熟悉的 Web2&#xff0c;投身于深邃、混亂卻…

【MySQL 數據庫】MySQL索引特性(一)磁盤存儲定位扇區InnoDB頁

文章目錄沒有索引&#xff0c;可能會有什么問題二、認識磁盤2.1 MySQL與存儲2.2 磁盤&#xff1a;2.3 扇區2.4 定位扇區2.5 結論三、三者作用流程&#xff08;磁盤&#xff0c;塊&#xff0c;InnoDB頁&#xff09;四、MySQL與磁盤交互基本單位五、建立共識&#x1f6a9;總結沒有…

2419. 按位與最大的最長子數組

Problem: 2419. 按位與最大的最長子數組 文章目錄思路解題過程復雜度Code思路 按位異或只會讓數值越來越小&#xff0c;因此最長的連續按位與的最大值只存在于連續最大值中。 解題過程 遍歷數組取出最大值&#xff0c;再遍歷找到每一次連續最大值&#xff0c;從中取出最長的連續…

基于Java(SpringBoot)+Vue+MySQL 實現(Web)的網絡課程平臺

基于 SpringBoot 的網絡課程平臺1 緒論1.1 引言本科題研究并實現了一個面向網絡學習的平臺&#xff0c;為需要學習的人提供了一個學習的平臺。任何人都課在本平臺進行注冊登錄&#xff0c;學習觀看視頻。本平臺是一個關于網絡課程學習平臺&#xff0c;學員科自主選擇視頻學習&a…

Centos7 | 防火墻(firewalld)使用ipset管理ip地址的集合

文章目錄一、firewalld中ipset的用途1.1 用途1.2 注意與iptables所用的ipset命令的不同&#xff0c;1.3 配置詳解二、firewalld中ipset的操作例子2.1 新建一個set2.2 在set中添加ip2.3 從set中刪除ip2.4 刪除一個set2.5 打印一個set的文件路徑2.6 打印一個set的內容2.8 判斷一個…

Day06_C++編程

01.思維導圖02.將鳥籠放飛所有鳥類的題&#xff0c;改成觀察者模式#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>//寫一個鳥類:有一個多…

【面試場景題】隨機立減金額計算

文章目錄背景設計思路方案結論高斯分布&#xff08;正態分布&#xff09;背景 某電商公司跟某銀行有合作&#xff0c;推進銀行信用卡辦卡&流水&#xff0c;使用此銀行信用卡用戶&#xff0c;支付可以隨機立減10&#xff5e;30元。其實公司每一筆都可獲得30元支付立減金&…

2025年湖北中級注冊安全工程師報考那些事

2025年湖北中級注冊安全工程師報考那些事各位從事建筑安全的人員看過來&#xff0c;注冊安全工程師是你們行業認可度較為高的證書。關于報考無論是安全相關專業跟不相關的專業都是可以報考的。只是年份要求不同。 本科&#xff1a;相關專業3年&#xff0c;不相關專業4年。 專科…

Prometheus + Grafana + Micrometer 監控方案詳解

這套組合是當前Java生態中最流行的監控解決方案之一&#xff0c;特別適合云原生環境下的微服務應用監控。下面我將從技術實現到最佳實踐進行全面解析。 一、技術棧組成與協作 1. 組件分工組件角色關鍵能力Micrometer應用指標門面(Facade)統一指標采集API&#xff0c;對接多種監…

實習小記(個人中心的編輯模塊)

實習小記&#xff08;個人中心的編輯模塊&#xff09; 項目需要加一個個人中心的編輯模塊&#xff0c;也是差不多搞了一天下來&#xff0c;其中遇到了很多問題&#xff0c;也是來記錄、分享一下。 技術棧&#xff1a;React、antd、TypeScript 需求 點擊編輯&#xff0c;彈出編…

【7】串口編程三種模式(查詢/中斷/DMA)韋東山老師學習筆記(課程聽不懂的話試著來看看我的學習筆記吧)

<1>前置概念補充在深入拆解三種模式前&#xff0c;先通過提供的 “函數對比表” 建立整體認知&#xff1a;這張表是串口收發的「武器庫索引」&#xff0c;清晰標注了查詢、中斷、DMA 三種模式下&#xff0c;收發 / 回調函數的對應關系。后續會結合實際代碼&#xff0c;講…

【Kubernetes 指南】基礎入門——Kubernetes 201(二)

二、滾動升級- 滾動升級&#xff08;Rolling Update&#xff09;通過逐個容器替代升級的方式來實現無中斷的服務升級&#xff1a;- 在滾動升級的過程中&#xff0c;如果發現了失敗或者配置錯誤&#xff0c;還可以隨時回滾&#xff1a;- 需要注意的是&#xff0c; kubectl rolli…

網絡資源模板--基于Android Studio 實現的圖書商城App

目錄 一、測試環境說明 二、項目簡介 三、項目演示 四、部設計詳情&#xff08;部分) 登錄注冊頁 首頁 五、項目源碼 一、測試環境說明 電腦環境 Windows 11 編寫語言 JAVA 開發軟件 Android Studio (2020) 開發軟件只要大于等于測試版本即可(近幾年官網直接下載…

JavaWeb 進階:Vue.js 與 Spring Boot 全棧開發實戰(Java 開發者視角)

作為一名 Java 開發工程師&#xff0c;當你掌握了 HTML、CSS 和 JavaScript 的基礎后&#xff0c;是時候接觸現代前端框架了。Vue.js 以其簡潔的 API、漸進式的設計和優秀的中文文檔&#xff0c;成為眾多 Java 開發者入門前端框架的首選。Vue.js 讓你能快速構建響應式、組件化的…

智能體產品化的關鍵突破:企業智能化轉型的“最后一公里”如何邁過?

智能體產品化的關鍵突破&#xff1a;企業智能化轉型的“最后一公里”如何邁過&#xff1f; 在人工智能迅猛發展的當下&#xff0c;智能體&#xff08;Agent&#xff09;成為企業數字化轉型的新引擎。無論是市場分析、客戶服務&#xff0c;還是自動化辦公&#xff0c;智能體都被…