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中的接口比較多,此處類似,只需要掌握如何正確的使用,然后再去深入研究背后的原理,已達到可擴展的能力。以下為list中一些常見的重要接口。

list的構造

請添加圖片描述

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 的副本
    list (InputIterator first, InputIterator last)
  • 解釋:構造一個容器,里面的元素是[first,last),里面的每個元素都來自這個范圍里對應的元素,順序相同 。
    list (const list& x)
  • 解釋:構造一個容器,其中包含 x 中每個元素的,順序相同。
  • 示例:
void test_list1()
{list<int> l1;                         // 構造空的l1list<int> l2(4, 100);                 // l2中放4個值為100的元素list<int> l3(l2.begin(), l2.end());  // 用l2的[begin(), end())左閉右開的區間構造l3list<int> l4(l3);                    // 用l3拷貝構造l4// 以數組為迭代器區間構造l5int array[] = { 16,2,77,29 };list<int> l5(array, array + sizeof(array) / sizeof(int));// 列表格式初始化C++11list<int> l6{ 1,2,3,4,5 };// 用迭代器方式打印l5中的元素list<int>::iterator it = l5.begin();while (it != l5.end()){cout << *it << " ";  //16 2 77 29++it;}cout << endl;// C++11范圍for的方式遍歷for (auto& e : l5)cout << e << " ";  //16 2 77 29cout << endl;
}

list的遍歷

// 注意:遍歷鏈表只能用迭代器和范圍for
void PrintList(const list<int>& l)
{// 注意這里調用的是list的 begin() const,返回list的const_iterator對象for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it){cout << *it << " ";// *it = 10; 編譯不通過}cout << endl;
}

1.list iterator的使用

此處,大家可暫時將迭代器理解成一個指針,該指針指向list中的某個節點。
iterator begin();const_iterator begin() const;
iterator end();const_iterator end() const;
reverse_iterator rbegin();const_reverse_iterator rbegin() const
reverse_iterator rend();const_reverse_iterator rend() const;
這里的使用方法和string、vector一樣,就不再過多介紹了。

注意
1.begin與end為正向迭代器,對迭代器執行++操作,迭代器向后移動
2.rbegin(end)與rend(begin)為反向迭代器,對迭代器執行++操作,迭代器向前移動


2.list capacity

empty
bool empty() const;

  • 解釋:檢測list是否為空,是返回true,否則返回false
  • 示例:
void test_list2()
{list<int> l1;list<int> l2;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);cout << l1.empty() << endl;  //0cout << l2.empty() << endl;  //1
}

size
size_type size() const;

  • 解釋:返回list中有效節點的個數
    用法跟前面的一樣,不在過多闡述。

3.list 的元素的訪問

front
reference front();const_reference front() const;

  • 解釋:返回list的第一個節點中值的引用
  • 示例:
void test_list3()
{list<int> mylist;mylist.push_back(77);mylist.push_back(22);// now front equals 77, and back 22mylist.front() -= mylist.back();cout << "mylist.front() is now " << mylist.front() << '\n';  //mylist.front() is now 55}

back
reference back();const_reference back() const;

  • 解釋:返回list的最后一個節點中值的引用
  • 示例:
void test_list3()
{list<int> mylist;mylist.push_back(10);while (mylist.back() != 0){mylist.push_back(mylist.back() - 1);}cout << "mylist contains:";for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)cout << ' ' << *it;  //mylist contains: 10 9 8 7 6 5 4 3 2 1 0
}

4.list的插入、刪除、交換、清空

push_front
請添加圖片描述

  • 解釋:在list首元素前插入值為val的元素
    pop_front
    請添加圖片描述

  • 解釋:刪除list中第一個元素
    push_back
    請添加圖片描述

  • 解釋:在list尾部插入值為val的元素
    pop_back
    請添加圖片描述

  • 解釋:刪除list中最后一個元素

  • 示例:

void test_list4()
{int array[] = { 1, 2, 3 };list<int> L(array, array + sizeof(array) / sizeof(array[0]));// 在list的尾部插入4,頭部插入0L.push_back(4);L.push_front(0);list<int>::iterator it = L.begin();while (it != L.end()){cout << *it << " ";  //0 1 2 3 4++it;}cout << endl;// 刪除list尾部節點和頭部節點L.pop_back();L.pop_front();list<int>::iterator it1 = L.begin();while (it1 != L.end()){cout << *it1 << " ";  //1 2 3++it1;}
}

insert
請添加圖片描述

  • 解釋:在position位置之前,插入值為val的元素。其它形式的用法和之前一樣。
    erase
    請添加圖片描述

  • 解釋:刪除position位置的值或者刪除某個區間的所有元素。

  • 示例:

void test_list5()
{//這里的PrintList(L)就是上面list的遍歷int array1[] = { 1, 2, 3 };list<int> L(array1, array1 + sizeof(array1) / sizeof(array1[0]));// 獲取鏈表中第二個節點auto pos = ++L.begin();cout << *pos << endl;  //2// 在pos前插入值為4的元素L.insert(pos, 4);PrintList(L);  //1 4 2 3// 在pos前插入5個值為5的元素L.insert(pos, 5, 5);PrintList(L);  //1 4 5 5 5 5 5 2 3// 在pos前插入[v.begin(), v.end)區間中的元素vector<int> v{ 7, 8, 9 };L.insert(pos, v.begin(), v.end());PrintList(L);  //1 4 5 5 5 5 5 7 8 9 2 3// 刪除pos位置上的元素L.erase(pos);PrintList(L);  //1 4 5 5 5 5 5 7 8 9 3// 刪除list中[begin, end)區間中的元素,即刪除list中的所有元素L.erase(L.begin(), L.end());PrintList(L);  //
}

swap
請添加圖片描述

  • 解釋交換兩個list中的元素。
    clear
    請添加圖片描述

  • 解釋:清空list中的有效元素。

  • 示例:

void test_list6()
{// 用數組來構造listint array1[] = { 1, 2, 3 };list<int> l1(array1, array1 + sizeof(array1) / sizeof(array1[0]));PrintList(l1);  //1 2 3// 交換l1和l2中的元素list<int> l2(3, 1);l1.swap(l2);PrintList(l1); //1 1 1PrintList(l2); //1 2 3// 將l2中的元素清空l2.clear();cout << l2.size() << endl;  //0
}

5.list的其它操作

sort
請添加圖片描述

  • 解釋:對列表中的元素進行排序,更改它們在容器中的位置。(默認是按照升序排列)
  • 示例:
void test_list7()
{list<int> l1 = { 3,2,1,4,5 };auto it = l1.begin();while (it != l1.end()){cout << *it << " ";  //3 2 1 4 5++it;}cout << endl;//升序排列:lessl1.sort();for (list<int>::iterator i = l1.begin(); i != l1.end(); i++){cout << *i << " ";  //1 2 3 4 5}
}

如果想按照降序排列,就按以下的方式寫。這里就先展示如何寫,到后面的學習在深入講解這個知識點,也就是“仿函數”。

void test_list7()
{list<int> l1 = { 3,2,1,4,5 };auto it = l1.begin();while (it != l1.end()){cout << *it << " ";++it;}cout << endl;//降序排列:greater//greater<int> gt;//l1.sort(gt);l1.sort(greater<int>());  //推薦這種寫法for (list<int>::iterator i = l1.begin(); i != l1.end(); i++){cout << *i << " ";  //5 4 3 2 1}
}

請添加圖片描述

  • 解釋:對[first,last)范圍內的元素進行排序。也可以通過迭代器對指定范圍內的元素進行排序。默認是按升序排序,當然也可以通過仿函數來按照降序排列。
  • 示例:
int main()
{vector<int> v = { 6,3,4,5,2,1,7,9,8 };sort(v.begin(), v.end());for (auto i : v){cout << i << " ";  //1 2 3 4 5 6 7 8 9}cout << endl;vector<int> v1 = { 3,2,4,5,6,8,1 };sort(v1.begin(), v1.begin() + 4);for (auto x : v1){cout << x << " ";  //2 3 4 5 6 8 1}return 0;
}

通過對list和算法庫里的sort對比。我們可以知道list里的排序沒法使用迭代器來進行排序,因為list的底層是帶頭雙向循環鏈表,當使用end()時,由于像vector和string里的迭代器不同,它們的end是最后一個元素的下一個位置,而在鏈表中,鏈表的物理空間并不連續,end的下一個數據就會指向頭結點。所以我們要對迭代器進行一定的封裝。讓迭代器符合統一的迭代器使用規則。
請添加圖片描述

那么如何進行封裝呢?等到list的模擬實現的時候在給各位細心講解。


unique
請添加圖片描述

  • 解釋:從容器中每個連續的相等元素組中刪除除第一個元素之外的所有元素,也就是去除重復元素。注意,只有當元素與緊接其前面的元素相等時,才會從列表容器中刪除該元素。因此,此函數對于排好序的列表特別有用。(只對于版本1)
  • 示例:
void test_list9()
{list<int> l1 = { 1,2,2,2,3,4,4,2,2,5 };l1.unique();auto i = l1.begin();while (i != l1.end()){cout << *i << " ";  //1 2 3 4 2 5++i;}cout << endl;list<int> l2 = { 1,1,3,4,2,5,5,5,6 };l2.sort();l2.unique();auto x = l2.begin();while (x != l2.end()){cout << *x << " ";  //1 2 3 4 5 6++x;}
}

reverse
請添加圖片描述

  • 解釋:逆置列表中元素的順序
  • 示例:
int main()
{list<int> mylist;for (int i = 1; i < 10; ++i) mylist.push_back(i);mylist.reverse();cout << "mylist contains:";for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)cout << ' ' << *it;  //mylist contains: 9 8 7 6 5 4 3 2 1return 0;
}

list的模擬實現

List的模擬實現

list迭代器失效問題

前面說過,此處大家可將迭代器暫時理解成類似于指針,迭代器失效即迭代器所指向的節點的無效,即該節點被刪除了。因為list的底層結構為帶頭結點的雙向循環鏈表,因此在list中進行插入時是不會導致list的迭代器失效的,只有在刪除時才會失效,并且失效的只是指向被刪除節點的迭代器,其他迭代器不會受到影響。

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

list與vector的對比

vector與list都是STL中非常重要的序列式容器,由于兩個容器的底層結構不同,導致其特性以及應用場景不同,其主要不同如下:

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

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

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

相關文章

生物信息學技能樹(Bioinformatics)與學習路徑

李升偉 整理 生物信息學是一門跨學科領域&#xff0c;涉及生物學、計算機科學以及統計學等多個方面。以下是關于生物信息學的學習路徑及相關技能的詳細介紹。 一、基礎理論知識 1. 生物學基礎知識 需要掌握分子生物學、遺傳學、細胞生物學等相關概念。 對基因組結構、蛋白質…

AOSP Android14 Launcher3——遠程窗口動畫關鍵類SurfaceControl詳解

在 Launcher3 執行涉及其他應用窗口&#xff08;即“遠程窗口”&#xff09;的動畫時&#xff0c;例如“點擊桌面圖標啟動應用”或“從應用上滑回到桌面”的過渡動畫&#xff0c;SurfaceControl 扮演著至關重要的角色。它是實現這些跨進程、高性能、精確定制動畫的核心技術。 …

超詳細實現單鏈表的基礎增刪改查——基于C語言實現

文章目錄 1、鏈表的概念與分類1.1 鏈表的概念1.2 鏈表的分類 2、單鏈表的結構和定義2.1 單鏈表的結構2.2 單鏈表的定義 3、單鏈表的實現3.1 創建新節點3.2 頭插和尾插的實現3.3 頭刪和尾刪的實現3.4 鏈表的查找3.5 指定位置之前和之后插入數據3.6 刪除指定位置的數據和刪除指定…

17.整體代碼講解

從入門AI到手寫Transformer-17.整體代碼講解 17.整體代碼講解代碼 整理自視頻 老袁不說話 。 17.整體代碼講解 代碼 import collectionsimport math import torch from torch import nn import os import time import numpy as np from matplotlib import pyplot as plt fro…

前端性能優化:所有權轉移

前端性能優化&#xff1a;所有權轉移 在學習rust過程中&#xff0c;學到了所有權概念&#xff0c;于是便聯想到了前端&#xff0c;前端是否有相關內容&#xff0c;于是進行了一些實驗&#xff0c;并整理了這些內容。 所有權轉移&#xff08;Transfer of Ownership&#xff09;…

Missashe考研日記-day23

Missashe考研日記-day23 0 寫在前面 博主前幾天有事回家去了&#xff0c;斷更幾天了不好意思&#xff0c;就當回家休息一下調整一下狀態了&#xff0c;今天接著開始更新。雖然每天的博客寫的內容不算多&#xff0c;但其實還是挺費時間的&#xff0c;比如這篇就花了我40多分鐘…

Docker 中將文件映射到 Linux 宿主機

在 Docker 中&#xff0c;有多種方式可以將文件映射到 Linux 宿主機&#xff0c;以下是常見的幾種方法&#xff1a; 使用-v參數? 基本語法&#xff1a;docker run -v [宿主機文件路徑]:[容器內文件路徑] 容器名稱? 示例&#xff1a;docker run -it -v /home/user/myfile.txt:…

HarmonyOS-ArkUI-動畫分類簡介

本文的目的是,了解一下HarmonyOS動畫體系中的分類。有個大致的了解即可。 動效與動畫簡介 動畫,是客戶端提升界面交互用戶體驗的一個重要的方式。可以使應用程序更加生動靈越,提高用戶體驗。 HarmonyOS對于界面的交互方面,圍繞回歸本源的設計理念,打造自然,流暢品質一提…

C++如何處理多線程環境下的異常?如何確保資源在異常情況下也能正確釋放

多線程編程的基本概念與挑戰 多線程編程的核心思想是將程序的執行劃分為多個并行運行的線程&#xff0c;每個線程可以獨立處理任務&#xff0c;從而充分利用多核處理器的性能優勢。在C中&#xff0c;開發者可以通過std::thread創建線程&#xff0c;并使用同步原語如std::mutex、…

區間選點詳解

步驟 operator< 的作用在 C 中&#xff0c; operator< 是一個運算符重載函數&#xff0c;它定義了如何比較兩個對象的大小。在 std::sort 函數中&#xff0c;它會用到這個比較函數來決定排序的順序。 在 sort 中&#xff0c;默認會使用 < 運算符來比較兩個對象…

前端配置代理解決發送cookie問題

場景&#xff1a; 在開發任務管理系統時&#xff0c;我遇到了一個典型的身份認證問題&#xff1a;??用戶登錄成功后&#xff0c;調獲取當前用戶信息接口卻提示"用戶未登錄"??。系統核心流程如下&#xff1a; ??用戶登錄??&#xff1a;調用 /login 接口&…

8.1 線性變換的思想

一、線性變換的概念 當一個矩陣 A A A 乘一個向量 v \boldsymbol v v 時&#xff0c;它將 v \boldsymbol v v “變換” 成另一個向量 A v A\boldsymbol v Av. 輸入 v \boldsymbol v v&#xff0c;輸出 T ( v ) A v T(\boldsymbol v)A\boldsymbol v T(v)Av. 變換 T T T…

【java實現+4種變體完整例子】排序算法中【冒泡排序】的詳細解析,包含基礎實現、常見變體的完整代碼示例,以及各變體的對比表格

以下是冒泡排序的詳細解析&#xff0c;包含基礎實現、常見變體的完整代碼示例&#xff0c;以及各變體的對比表格&#xff1a; 一、冒泡排序基礎實現 原理 通過重復遍歷數組&#xff0c;比較相鄰元素并交換逆序對&#xff0c;逐步將最大值“冒泡”到數組末尾。 代碼示例 pu…

系統架構設計(二):基于架構的軟件設計方法ABSD

“基于架構的軟件設計方法”&#xff08;Architecture-Based Software Design, ABSD&#xff09;是一種通過從軟件架構層面出發指導詳細設計的系統化方法。它旨在橋接架構設計與詳細設計之間的鴻溝&#xff0c;確保系統的高層結構能夠有效指導后續開發。 ABSD 的核心思想 ABS…

Office文件內容提取 | 獲取Word文件內容 |Javascript提取PDF文字內容 |PPT文檔文字內容提取

關于Office系列文件文字內容的提取 本文主要通過接口的方式獲取Office文件和PDF、OFD文件的文字內容。適用于需要獲取Word、OFD、PDF、PPT等文件內容的提取實現。例如在線文字統計以及論文文字內容的提取。 一、提取Word及WPS文檔的文字內容。 支持以下文件格式&#xff1a; …

Cesium學習筆記——dem/tif地形的分塊與加載

前言 在Cesium的學習中&#xff0c;學會讀文檔十分重要&#xff01;&#xff01;&#xff01;在這里附上Cesium中英文文檔1.117。 在Cesium項目中&#xff0c;在平坦坦地球中加入三維地形不僅可以增強真實感與可視化效果&#xff0c;還可以??提升用戶體驗與交互性&#xff0c…

Spring Boot 斷點續傳實戰:大文件上傳不再怕網絡中斷

精心整理了最新的面試資料和簡歷模板&#xff0c;有需要的可以自行獲取 點擊前往百度網盤獲取 點擊前往夸克網盤獲取 一、痛點與挑戰 在網絡傳輸大文件&#xff08;如視頻、數據集、設計稿&#xff09;時&#xff0c;常面臨&#xff1a; 上傳中途網絡中斷需重新開始服務器內…

數碼管LED顯示屏矩陣驅動技術詳解

1. 矩陣驅動原理 矩陣驅動是LED顯示屏常用的一種高效驅動方式&#xff0c;利用COM&#xff08;Common&#xff0c;公共端&#xff09;和SEG&#xff08;Segment&#xff0c;段選&#xff09;線的交叉點控制單個LED的亮滅。相比直接驅動&#xff0c;矩陣驅動可以顯著減少所需I/…

【上位機——MFC】菜單類與工具欄

菜單類 CMenu&#xff0c;封裝了關于菜單的各種操作成員函數&#xff0c;另外還封裝了一個非常重要的成員變量m_hMenu(菜單句柄) 菜單使用 添加菜單資源加載菜單 工具欄相關類 CToolBarCtrl-》父類是CWnd&#xff0c;封裝了關于工具欄控件的各種操作。 CToolBar-》父類是CC…

liunx中常用操作

查看或修改linux本地mysql端口 cat /etc/my.cnf 如果沒有port可以添加&#xff0c;有可以修改 查看本地端口占用情況 bash netstat -nlt | grep 3307 HADOOP集群 hdfs啟動與停止 # 一鍵啟動hdfs集群 start-dfs.sh # 一鍵關閉hdfs集群 stop-dfs.sh #除了一鍵啟停外&#x…