第九講:C++中的list與forward_list

目錄

1、list的介紹及使用

1.1、構造及賦值重載

1.2、迭代器

1.3、空間

1.4、訪問

1.5、修改

1.6、操作

2、迭代器失效

3、list的模擬實現

4、forward_list介紹與使用

4.1、構造及賦值重載

4.2、迭代器

4.3、容量

4.4、訪問

4.5、修改

4.6、操作

5、迭代器的分類

5.1、按功能分類

5.2、按性質分類

6、list與vector的對比


1、list的介紹及使用

template < class T, class Alloc = allocator<T> > class list;

list文檔介紹

list的底層是帶頭雙向鏈表結構,雙向鏈表中每個元素存儲在獨立節點中,在節點中通過指針指向其前一個元素和后一個元素。list與forward_list非常相似,最主要的不同在于forward_list是無頭單向鏈表。

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

1.1、構造及賦值重載

explicit list (const allocator_type& alloc = allocator_type()); // 默認構造explicit list (size_type n, const value_type& val = value_type(), const allocator_type& alloc = allocator_type()); // 構造n個val值template <class InputIterator>  
list (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()); // 迭代器區間構造list (const list& x); // 拷貝構造list& operator= (const list& x); // 賦值重載

1.2、迭代器

iterator begin();
iterator end();const_iterator begin() const;
const_iterator end() const;reverse_iterator rbegin();
reverse_iterator rend();const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;

例如:?

int main()
{list<int> lt1;list<int> lt2(10, 2);list<int> lt3(lt2.begin(), lt2.end());list<int> lt4(lt3);lt1 = lt4;list<int>::iterator it1 = lt1.begin();while (it1 != lt1.end()){cout << *it1 << ' ';++it1;}cout << endl;for (auto e : lt4){cout << e << ' ';}cout << endl;return 0;
}

1.3、空間

bool empty() const; // 判斷是否為空size_type size() const; // 元素個數

例如:?

int main()
{list<int> lt1;list<int> lt2(10, 2);cout << lt1.empty() << endl;cout << lt2.empty() << endl;cout << lt1.size() << endl;cout << lt2.size() << endl;return 0;
}

1.4、訪問

reference front(); // 起始元素
const_reference front() const;reference back(); // 末尾元素
const_reference back() const;

例如:?

int main()
{list<int> lt1(10, 2);lt1.front()++;lt1.back()--;cout << lt1.front() << endl;cout << lt1.back() << endl;return 0;
}

1.5、修改

void push_front (const value_type& val); // 頭插
void pop_front(); // 頭刪void push_back (const value_type& val); // 尾插
void pop_back(); // 尾刪iterator insert (iterator position, const value_type& val); // 插入iterator erase (iterator position); // 刪除void swap (list& x); // 交換void resize (size_type n, value_type val = value_type()); // 改變元素的個數void clear(); // 清空

例如:?

int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_front(5);lt.push_front(6);for (auto e : lt){cout << e << ' ';}cout << endl;lt.resize(10, 9);lt.insert(lt.begin(), 7);for (auto e : lt){cout << e << ' ';}cout << endl;list<int> lt2(lt);lt.clear();for (auto e : lt2){cout << e << ' ';}cout << endl;lt.swap(lt2);for (auto e : lt){cout << e << ' ';}cout << endl;lt.pop_front();lt.pop_back();for (auto e : lt){cout << e << ' ';}cout << endl;return 0;
}

1.6、操作

void sort(); // 排序,默認是升序template <class Compare>
void sort (Compare comp); // 關于仿函數,后面再說void reverse(); // 逆置

例如:

int main()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_front(5);lt.push_front(6);lt.reverse();list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << ' ';++it;}cout << endl;list<int> lt2(lt);lt.sort();for (auto e : lt){cout << e << ' ';}cout << endl;greater<int> gt;lt2.sort(gt);for (auto e : lt2){cout << e << ' ';}cout << endl;return 0;
}

2、迭代器失效

前面說過,迭代器失效即迭代器所指向的節點的無效。因為list的底層結構為帶頭結點的雙向循環鏈表,因此在list中進行插入時是不會導致list的迭代器失效的,只有在刪除時才會失效,并且失效的只是指向被刪除節點的迭代器,其他迭代器不會受到影響。例如:

int main()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> lt(array, array + sizeof(array) / sizeof(array[0]));auto it = lt.begin();while (it != lt.end()){// erase()函數執行后,it所指向的節點已被刪除,因此it無效,在下一次使用it時,必須先給其賦值lt.erase(it);++it;}return 0;
}

當運行到++it時就會報錯。?改為如下即可:

int main()
{int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };list<int> lt(array, array + sizeof(array) / sizeof(array[0]));auto it = lt.begin();while (it != lt.end()){lt.erase(it++); //或者也可以寫成://it = lt.erase(it);}for (auto e : lt){cout << e << ' ';}cout << endl;return 0;
}

3、list的模擬實現

template<class T>
struct list_node
{list_node<T>* _prev;list_node<T>* _next;T _data;list_node(const T& x = T()):_prev(nullptr),_next(nullptr),_data(x){}
};// ///////////////////////////////////////////////////////////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){}self& operator++(){_node = _node->_next;return *this;}self& operator--(){_node = _node->_prev;return *this;}self& operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}Ref operator*()               {return _node->_data;}Ptr operator->()                 {return &_node->_data;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}
};// /////////////////////////////////////////template<class T>
class List
{
public:typedef list_node<T> Node;// 正向迭代器typedef __list_iterator<T,T&,T*> iterator;typedef __list_iterator<T,const T&,const T*> const_iterator;// //////////////////////////////////////////////////////iterator begin(){return _head->_next;//這里也可以寫為:iterator(_head->_next);}iterator end(){return _head;//這里也可以寫為:iterator(_head);}const_iterator begin() const{return _head->_next;}const_iterator end() const{return _head;}// ///////////////////////////////////////////////////////////void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}List(){empty_init();}List(const List<T>& lt){empty_init();const_iterator it = lt.begin();while (it != lt.end()){push_back(*it);++it;}//像下面這樣寫也是可以的/*for (auto e : lt){push_back(e);}*/}/*List<T>& operator=(const List<T>& lt) // 傳統寫法{if (this != &lt){clear();for (auto e : lt){push_back(e);}}return *this;}*/void swap(List<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}List<T>& operator=(List<T> lt) // 現代寫法{swap(lt);return *this;}iterator insert(iterator pos, const T& x){Node* newnode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;++_size;return iterator(newnode);}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}void pop_back(){erase(--end());}~List(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;delete cur;prev->_next = next;next->_prev = prev;--_size;return iterator(next);}void push_back(const T& x){Node* newnode = new Node(x);Node* end = _head->_prev;end->_next = newnode;newnode->_prev = end;newnode->_next = _head;_head->_prev = newnode;_size++;}size_t size(){return _size;}private:Node* _head;size_t _size;
};

4、forward_list介紹與使用

template < class T, class Alloc = allocator<T> > class forward_list;

forward_list文檔介紹

forward_list的底層結構是無頭單向鏈表。

4.1、構造及賦值重載

//默認構造
explicit forward_list (const allocator_type& alloc = allocator_type());//構造n個val
explicit forward_list (size_type n, const value_type& val,const allocator_type& alloc = allocator_type());
//用迭代區間構造
template <class InputIterator>
forward_list (InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());//拷貝構造
forward_list (const forward_list& fwdlst);//賦值重載
forward_list& operator= (const forward_list& fwdlst);

4.2、迭代器

iterator before_begin() noexcept; // 返回容器第一個元素之前的位置
const_iterator before_begin() const noexcept;iterator begin() noexcept; // 返回第一個元素的位置
const_iterator begin() const noexcept;iterator end() noexcept; // 返回最后一個元素之后的位置
const_iterator end() const noexcept;

例如:?

int main()
{   forward_list<int> f1;forward_list<int> f2(5, 3);forward_list<int> f3(f2.begin(), f2.end());forward_list<int> f4(f3);f1 = f4;forward_list<int>::iterator it1 = f2.begin();while (it1 != f2.end()){cout << *it1 << ' ';++it1;}cout << endl;for (auto& e : f3){cout << ++e << ' ';}cout << endl;return 0;
}

4.3、容量

bool empty() const noexcept; // 判斷是否為空

4.4、訪問

reference front(); // 返回第一個元素
const_reference front() const;

4.5、修改

void push_front (const value_type& val); //頭插void pop_front(); // 頭刪iterator insert_after ( const_iterator position, const value_type& val ); // 之后插入iterator erase_after (const_iterator position); // 之后刪除void swap (forward_list& fwdlst); // 交換void resize (size_type n); // 增大元素個數
void resize (size_type n, const value_type& val);void clear() noexcept; // 清空

例如:?

int main()
{   forward_list<int> f1;f1.push_front(1);f1.push_front(2);f1.push_front(3);f1.push_front(4);f1.push_front(5);cout << f1.empty() << endl;cout << f1.front() << endl;f1.insert_after(f1.before_begin(), 6);forward_list<int>::iterator it1 = f1.begin();while (it1 != f1.end()){cout << *it1 << ' ';++it1;}cout << endl;forward_list<int> f2;f2.resize(10, 5);f1.swap(f2);f2.clear();for (auto e : f1){cout << e << ' ';}cout << endl;return 0;
}

4.6、操作

void sort(); // 排序,默認為升序template <class Compare>
void sort (Compare comp);void reverse() noexcept; // 逆置

例如:

int main()
{   forward_list<int> f1;f1.push_front(5);f1.push_front(4);f1.push_front(3);f1.push_front(5);f1.push_front(2);f1.sort();for (auto e : f1){cout << e << ' ';}cout << endl;f1.reverse();for (auto e : f1){cout << e << ' ';}cout << endl;return 0;
}

5、迭代器的分類

5.1、按功能分類

迭代器按功能分類可以分為正向迭代器反向迭代器。關于反向迭代器,會在模板進階部分進行模擬實現。

5.2、按性質分類

迭代器按性質(由容器的底層實現決定的)分類可以分為單向迭代器、雙向迭代器以及隨機迭代器。

單向迭代器:只支持++,不支持--,例如:forward_list(單鏈表)。

雙向迭代器:支持++,也支持--,例如:list(雙向鏈表)

隨機迭代器:支持++,也支持--,還支持+以及-,例如:vector(順序表)、string(順序表)以及deque(后面講)。

例如:算法庫中有一個sort模板函數,用來進行排序

template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);	template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

但是該模板函數不能用來對list以及forward_list進行排序,因為該模板函數要求的是傳隨機迭代器,這也就是為什么,明明算法庫中有sort模板函數,但是forward_list以及list中也實現了sort函數的原因。

6、list與vector的對比

vectorlist
底層結構動態順序表,一段連續空間帶頭結點的雙向循環鏈表
隨機訪問支持隨機訪問,訪問某個元素效率O(1)不支持隨機訪問,訪問某個元素效率為O(N)
插入和刪除任意位置插入和刪除效率低,需要搬移元素,時間復雜度為O(N),插入時有可能需要增容,增容會開辟新空間、拷貝元素以及釋放舊空間,導致效率更低任意位置插入和刪除效率高,不需要搬移元素,時間復雜度為 O(1)
空間利用率底層為連續空間,不容易造成內存碎片,空間利用率高,緩存利用率高。底層節點動態開辟,節點容易造成內存碎片,空間利用率低, 緩存利用率低。
迭代器原生態指針對原生態指針進行封裝
迭代器失效在插入元素后,要給迭代器重新賦值,因為插入元素有可能會導致重新擴容,致使原來迭代器失效。刪除后,迭代器需要重新賦值否則會失效。插入元素不會導致迭代器失效, 刪除元素時,只會導致當前迭代器失效,其他迭代器不受影響。
使用場景需要高效存儲,隨機訪問,不關心插入刪除效率。大量插入和刪除操作,不關心隨機訪問。

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

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

相關文章

華為云數據庫 GaussDB的 nvarchar2隱式類型轉換的坑

bigint 與 nvarchar2比較時發生隱式類型轉換的坑 1. 案例分析 假設&#xff1a; table1有下面兩個字段&#xff1a;id:bigint&#xff0c; source_id nvarchar2(50)數據庫中id 的值一定大于 int4 的最大值&#xff0c;例如存在一條單據&#xff1a; id1947854462980792321&…

spring boot 集成netty,及其一些基本概念

一、基本概念 1、channel:通道&#xff0c;入站或者出站數據的載體 2、ChannelHandler&#xff1a;通道處理器&#xff0c;業務邏輯寫在這里面&#xff0c;netty 5版本將入戰和出站合并成了ChannelHandler 3、ChannelPipeline&#xff1a;通道里的管道&#xff0c;是一個或者多…

7月23日華為機考真題第一題100分

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? bishipass.com 01. 創業投資收益優化 問題描述 K小姐剛剛大學畢業,手頭有 m m m 元資金想要進行創業投資。她發現了 k k

HTML5 跨文檔通信機制:postMessage API 詳解與應用

postMessage 是 HTML5 規范中定義的跨文檔通信&#xff08;Cross-Document Messaging&#xff09;API&#xff0c;其設計目的是解決不同源&#xff08;協議、域名、端口任一存在差異&#xff09;的窗口&#xff08;如 iframe 嵌入的文檔、window.open 創建的新窗口&#xff09;…

Kafka——Kafka中的位移提交

引言&#xff1a;為什么位移提交至關重要&#xff1f;在Kafka的分布式消息系統中&#xff0c;消費者組&#xff08;Consumer Group&#xff09;通過分區分配機制實現負載均衡和容錯&#xff0c;但如何準確記錄每個消費者的消費進度&#xff0c;是保證消息不丟失、不重復的關鍵。…

java設計模式 -【裝飾器模式】

裝飾器模式的定義 裝飾器模式&#xff08;Decorator Pattern&#xff09;是一種結構型設計模式&#xff0c;允許向一個現有對象動態添加新功能&#xff0c;同時不改變其結構。它通過創建包裝對象&#xff08;裝飾器&#xff09;來包裹原始對象&#xff0c;并在保持原始對象方法…

手寫字體生成器:一鍵模擬真實筆跡

軟件介紹 在自媒體創作領域&#xff0c;手寫體文案因其獨特的藝術感而備受青睞。然而&#xff0c;真實的手寫往往效率低下且效果難以保證。今天為大家推薦一款專業的手寫模擬軟件&#xff0c;能夠一鍵生成逼真的手寫字體效果&#xff0c;完美解決創作效率與質量的雙重需求。…

【Android】用 ViewPager2 + Fragment + TabLayout 實現標簽頁切換

文章目錄【Android】用 ViewPager2 Fragment TabLayout 實現標簽頁切換一、引入&#xff1a;什么是 ViewPager2 &#xff1f;二、ViewPager2 的基礎使用1. 在布局文件 (activity_main.xml)中添加 ViewPager22. 制作一個 Fragment2.1 創建一個布局文件2.2 創建一個 Fragment 類…

嵌入式學習-土堆目標檢測(4)-day28

Pytorch中加載自定義數據集 - VOC其中需要pip install xmltodict#voc_dataset.pyimport os import torch import xmltodict from PIL import Image from torch.utils.data import Dataset import torchvision.transforms as transformsclass VOCDataset(Dataset): def __init_…

Spring MVC上下文容器在Web容器中是如何啟動的(源碼深入剖析)?

文章目錄一、雙容器架構&#xff1a;MVC容器與根容器的關系二、啟動全流程解析1. 啟動流程全景圖2. 初始化根容器&#xff08;Root WebApplicationContext&#xff09;2.1 Tomcat 中啟動入口源碼解析2.2 Spring 根上下文啟動源碼解析3. 初始化 MVC 容器&#xff08;DispatcherS…

【iOS】編譯和鏈接、動靜態庫及dyld的簡單學習

文章目錄編譯和鏈接1??核心結論&#xff1a;一句話區分2??編譯過程&#xff1a;從源代碼到目標文件&#xff08;.o&#xff09;2.1 預處理&#xff08;Preprocessing&#xff09;&#xff1a;“替換變量復制粘貼”2.2 編譯&#xff08;Compilation&#xff09;&#xff1a;…

金山辦公WPS項目產品總監陳智新受邀為第十四屆中國PMO大會演講嘉賓

全國PMO專業人士年度盛會珠海金山辦公軟件有限公司WPS項目產品總監 陳智新先生 受邀為“PMO評論”主辦的2025第十四屆中國PMO大會演講嘉賓&#xff0c;演講議題為&#xff1a;中小團隊PMO的成長之路&#xff0c;敬請關注&#xff01;議題簡要&#xff1a;在競爭激烈、需求多變的…

web安全 | docker復雜環境下的內網打點

本文作者&#xff1a;Track-syst1m一.前言本文涉及的相關漏洞均已修復、本文中技術和方法僅用于教育目的&#xff1b;文中討論的所有案例和技術均旨在幫助讀者更好地理解相關安全問題&#xff0c;并采取適當的防護措施來保護自身系統免受攻擊。二.大概流程1. 外網打點? 漏洞利…

iTwin 幾何屬性獲取

面積體積半徑獲取幾何屬性&#xff0c;如面積&#xff0c;體積&#xff0c;半徑&#xff0c;可以使用getMassProperties這個接口async onGetMassProperty(){const vp IModelApp.viewManager.selectedView;const iModel vp?.iModel;if (!iModel) return;console.log("iM…

OpenLayers 快速入門(九)Extent 介紹

看過的知識不等于學會。唯有用心總結、系統記錄&#xff0c;并通過溫故知新反復實踐&#xff0c;才能真正掌握一二 作為一名摸爬滾打三年的前端開發&#xff0c;開源社區給了我飯碗&#xff0c;我也將所學的知識體系回饋給大家&#xff0c;助你少走彎路&#xff01; OpenLayers…

LeetCode 121. 買賣股票的最佳時機 LeetCode 122. 買賣股票的最佳時機II LeetCode 123.買賣股票的最佳時機III

LeetCode 121. 買賣股票的最佳時機嘗試一&#xff1a;暴力解決方法常用兩個指針去遍歷prices數組&#xff0c;dp[i]用于記錄在第i天所獲得的最大利潤。時間復雜度是O(N^2)&#xff0c;超出時間限制。Codeclass Solution(object):def maxProfit(self, prices):"""…

【LeNet網絡架構】——深度學習.卷積神經網絡

目錄 1 MLP 2 LeNet簡介 3 Minst數據集 3.1 MINST數據集簡介 3.2 MNIST數據集的預處理 4 LeNet手寫數字識別 LeNet由Yann Lecun 提出&#xff0c;是一種經典的卷積神經網絡&#xff0c;是現代卷積神經網絡的起源之一。Yann將該網絡用于郵局的郵政的郵政編碼識別&#xff…

Python筆記完整版

常用pip源 &#xff08;1&#xff09;阿里云 http://mirrors.aliyun.com/pypi/simple/&#xff08;2&#xff09;豆瓣 http://pypi.douban.com/simple/&#xff08;3&#xff09;清華大學 https://pypi.tuna.tsinghua.edu.cn/simple/&#xff08;4&#xff09;中國科學技術大學…

2025 鴻蒙創新賽又來了,萬少教你如何強勢切入 HarmonyOS AI特性

2025 鴻蒙創新賽又來了&#xff0c;萬少教你如何強勢切入 前言 ? 2025 華為HarmonyOS 創新賽又來了&#xff0c;創新賽是鴻蒙生態最大規模開發者官方賽事&#xff0c;最高獲百萬激勵。 參賽資格 面向所有開發者開放以隊伍的形式來參加&#xff0c;可以一個人報名一個隊伍&a…

【智能模型系列】Unity通過訪問Ollama調用DeepSeek模型進行本地部署

【智能模型系列】Unity通過訪問Ollama調用DeepSeek模型進行本地部署 目錄 一、前言 二、環境準備 三、核心代碼解析 1、參數配置 2. CallDeepSeek.cs - API交互控制器 3、 MainPanel.cs - 用戶界面控制器 四、源碼 一、前言 在本教程中,我將分享如何在Unity中集成本地…