C++——list的簡要介紹

list的介紹

詳細請看(https://cplusplus.com/reference/list/list/?kw=list)

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

2.list的底層實質是一個雙向鏈表結構,雙向鏈表里每個元素的存放都互不相關,在節點中可以通過指針來指向前一個元素和后一個元素

3.相對于vector等序列式容器,list在任意位置上的插入、刪除元素的效率會更高。

4.但是list與其他序列式容器相比,最大缺陷是不支持任意位置的隨機訪問,必須要從已知位置迭代到當前的位置,只有這樣才可以進行數據的讀取。

簡要使用

建立及其數據的尾插

void test_list1()
{list<int> l1;l1.push_back(1);l1.push_back(2);l1.push_back(3);l1.push_back(4);l1.push_back(5);list<int>::iterator it = l1.begin();//讀取需要用迭代器讀取,不能用下標while (it != l1.end()){cout << *it << " ";++it;}cout << endl;for (auto e : l1){cout << e << " ";}cout << endl;
}

排序

list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
l1.push_back(5);l1.reverse();//進行了逆序
l1.sort();//默認升序//降序
greater<int> gt;
l1.sort(gt);//傳入這個即可l1.sort(greater<int>());//也可以用匿名函數//升序限定范圍
sort(v.begin(), v.end());

數據的拷貝

lt2.assign(v.begin(), v.end());//粘貼

去重函數

list<int> L;
L.push_back(1);
L.push_back(4);
L.push_back(3);
L.push_back(3);L.unique();
//但在注意的是,去重函數本質是用一個雙指針進行刪除,連續相同的會留下一個,若是多個重復數據,若不是連//續的,那么結果還是會出現重復的元素。
//——所以需要先進行排序sort

分割函數

list<int> l1, l2;
for (int i = 1; i <= 4; i++)
{l1.push_back(i);
}
for (int i = 5; i <= 8; i++)
{l2.push_back(i);
}auto it = l1.begin();
l1.splice(it, l2);//將l2中的數據,全部插入到l1的it處

list的模擬實現

現在復現list類的簡要底層代碼——實現的結構體邏輯和用C實現相似。

namespace bit
{template<class T>struct list_node//節點的結構,并且對節點進行初始化{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& x = T())
//給缺省值,由于不知道是什么類型,所以用模板名T進行位置類型變量的初始化(作為缺省)->T():_data(x),_next(nullptr),_prev(nullptr){}};template<class T>class list//鏈表的結構,需要一個頭結點即可{typedef list_node<T> Node;public:private:Node* _head;};
}

構造函數

void empty_init()
{_head=new Node;_head->_next=_head;_head->_prev=_head;
}list()
{empty_init();
}

尾插

void push_back(const T& x)
{Node*tail=_head->_prev;Node* newnode=new Node(x);//建立一個包含x的節點tail->_next=newnode;newnode->_prev=tail;newnode->_next=_head;_head->_prev=newnode;++_size;
}

節點迭代器

倘若我們有以下的代碼

list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
l1.push_back(5);list<int>::iterator it = l1.begin();
while (it != l1.end())
{cout << *it << " ";++it;
}

這樣子會顯示報錯?這是為什么?——結構體存放的是結點,解引用出來的是一整個結構體

而且節點存放的空間不是連續存放的,所以需要寫一個結構體,進行對于' 節點的指針 '的封裝。

template<class T>
struct _list_iterator
{    typedef _list_iterator<T> self;typedef list_node<T> Node;Node* _node;//結構體里存放的就是節點
}

迭代器的構造

_list_iterator(Node* node)//此迭代器的本質也就是用節點的指針:_node(node)
{}

節點指針++

 self& operator()
{_node=_node->next;return *this;
}

解引用獲取數據

T& operator*()//解引用也要進行一個函數的封裝,要的是這個數據,所以用T
{return _node->_data;	
}

指針的比較

bool operator!=(const self& s)//結點之間比較,所以用迭代器的結構體名稱
{return _node != s._node;
}

list類

有了迭代器之后,對于list類作補充

template<class T>
class list
{
public:typedef _list_iterator<T> iterator;iterator begin(){return _head->_next;}iterator end(){return _head;}}

插入

iterator insert(iterator pos, const T& val)//由于插入是利用節點之間的連接進行的,且需要用迭代器
{Node* cur=pos._node;Node* newnode=new Node(val);Node* prev=cur->_prev;prev->_next=newnode;newnode->_prev=prev;newnode->_next=cur;cur->_prev=newnode;++_size;return iterator(newnode);//insert插入函數的結果會返回插入節點的位置
}

刪除

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);//erase要返回下一個元素的指針
}

有了insert和erase后,可以方便地實現其他函數

void push_front(const T& x)//頭插
{insert(begin(), x);
}
void pops_front(const T& x)//頭刪
{erase(begin());
}
void pops_back(const T& x)//尾刪
{erase(end());
}

清理函數

void clear()
{iterator it=begin();while(it!=end()){it=erase(it);//erase會返回一個指向下一個位置的地址,用erase可以減少代碼量}
}

拷貝重載/賦值拷貝

void swap(list<T>& lt)
{std::swap(_head, lt._head);std::swap(_size, lt._size);
}list<int>& operator=(list<int>& lt)
{swap(lt);return *this;
}list(const list<T>& lt)
{empty_init();for (auto e : lt){push_back(e);//直接用push_back進行數據的插入即可,不需要再作拷貝結點}
}

析構函數

~list()
{clear();delete _head;_head = nullptr;
}

完善節點指針的結構體

template<class T>//用一個迭代器的結構體進行結點的封裝 ++
//struct 默認公有,但是class類需要做些聲明
struct _list_iterator
{typedef list_node<T> Node;typedef _list_iterator<T> self;Node* _node;//創造一個結點_list_iterator(Node* node)//用一個結點的指針就能夠造出一個迭代器:_node(node)//傳入begin,就會有對應位置的一個初始化結點出來{}self& operator++()//迭代器++{_node = _node->_next;return *this;}self operator++(int)//后置++{self 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;}T& operator*()//解引用也要進行一個函數的封裝,要的是這個數據,所以用T{return _node->_data;}T* operator->(){return &_node->_data;}bool operator!=(const self& s)//結點之間比較,所以用迭代器的結構體名稱{return _node != s._node;}bool operator==(const self& s)//結點之間比較,所以用迭代器的結構體名稱{return _node == s._node;}
};

const迭代器

我們知道,若無const修飾,那么就可以進行' 讀寫 ',若有const修飾,那么就只能進行' 讀 '。

倘若用const修飾迭代器呢?(const iterator)——err,這樣子會是迭代器本身不能修改,那么應該怎么表示?

——const_iterator 重新定義的一個類型,這樣本身可以修改,指向的內容不能修改。

那么可以在迭代器基礎上進行修改,成為const迭代器

template<class T>//用一個迭代器的結構體進行結點的封裝 ++
//struct 默認公有,但是class類需要做些聲明
struct _list_const_iterator
{typedef list_node<T> Node;typedef _list_const_iterator<T> self;Node* _node;_list_const_iterator(Node* node):_node(node){}self& operator++()//迭代器++{_node = _node->_next;return *this;}self operator++(int)//后置++{self 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;}//加上const修改后,迭代器里的內容就不能被修改const T& operator*()//解引用也要進行一個函數的封裝,要的是這個數據,所以用T{return _node->_data;}const T* 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 Ref,class Ptr>
struct _list_iterator
{typedef list_node<T> Node;typedef _list_iterator<T,Ref,Ptr> self;//模板中的類型T,可以用Ref和Ptr來分別取代//其中,T& 又可以被Ref代替  T* 可以被Ptr代替Node* _node;//創造一個結點_list_iterator(Node* node)//用一個結點的指針就能夠造出一個迭代器:_node(node)//傳入begin,就會有對應位置的一個初始化結點出來{}self& operator++()//迭代器++{_node = _node->_next;return *this;}self operator++(int)//后置++{self 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;}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;}
};

那么對于list類,要通過兩個模板參數進行相關的控制

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;iterator begin(){return iterator(_head->_next);//兩種寫法}iterator end(){return _head;}const_iterator begin()const{return const_iterator(_head->_next);}const_iterator end()const{return _head;}
....//
}

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

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

相關文章

jenkins 安裝和通過gitee 拉取PHP項目

#jenkins 安裝地址&#xff1a;https://pkg.jenkins.io/redhat-stable/sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key yum install fontconfig…

2023年國賽數學建模思路 - 復盤:光照強度計算的優化模型

文章目錄 0 賽題思路1 問題要求2 假設約定3 符號約定4 建立模型5 模型求解6 實現代碼 建模資料 0 賽題思路 &#xff08;賽題出來以后第一時間在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 問題要求 現在已知一個教室長為15米&#xff0c;寬為12米&…

Thymeleaf快速入門及其注意事項

&#x1f600;前言 本篇博文是關于Thymeleaf的基本介紹&#xff0c;希望你能夠喜歡&#x1f60a; &#x1f3e0;個人主頁&#xff1a;晨犀主頁 &#x1f9d1;個人簡介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以幫助到大家&#xff0c;您的滿意是我的…

Dev-C++

文章目錄 介紹使用教程常用快捷鍵文件部分格式部分行操作跳轉部分顯示部分運行部分調試部分 調試流程 擴展增加編譯選項開啟優化顯示最多警告信息生成調試信息 編譯小 trick開大棧定義宏代碼格式化 美化字體主題 介紹 Dev-C 是一套用于開發 C/C 程序的自由的集成開發環境&…

面向云思考安全

Gartner最近的一項研究表明&#xff0c;到 2025 年&#xff0c;85% 的企業會采用云戰略&#xff0c;雖然這一數字是面向全球的&#xff0c;但可以看到在中國的環境中&#xff0c;基于云所帶來的優勢&#xff0c;越來越多的企業也同樣開始積極向云轉型。 但同時&#xff0c;有報…

BBS項目day02、注冊、登錄(登錄之隨機驗證碼)、修改密碼、退出登錄、密碼加密加鹽

一、注冊 1.注冊之前端頁面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>注冊頁面</title><!--動態引入文件-->{% load static %}<script src"{% static js/jquery.min.js %…

【springmvc系】利用RequestBodyAdviceAdapter做接口鑒權

需求 有個簡單的需求&#xff0c;對于第三方接口我們需要做個簡單的鑒權機制&#xff0c;這邊使用的是非對稱性加密的機制。我們提供三方公鑰&#xff0c;他們通過公鑰對接口json報文使用加密后的報文請求&#xff0c;我們通過對接收過來的請求某一個加密報文字段來進行RSA解密…

婚戀交友h5多端小程序開源版開發

婚戀交友h5多端小程序開源版開發 以下是婚戀交友H5多端小程序的功能列表&#xff1a; 用戶注冊和登錄&#xff1a;用戶可以通過手機號碼或第三方賬號注冊和登錄。個人信息填寫&#xff1a;用戶可以填寫個人基本信息&#xff0c;包括姓名、性別、年齡、身高、體重、學歷、職業等…

Java課題筆記~ 數據提交的方式

前四種數據注入的方式&#xff0c;會自動進行類型轉換。但無法自動轉換日期類型。 &#xff08;1&#xff09;單個數據&#xff08;基本數據類型&#xff09;注入 在方法中聲明一個和表單提交的參數名稱相同的參數&#xff0c;由框架按照名稱直接注入。 &#xff08;2&#x…

微信小程序nfc指令異常記錄

小程序nfc相關代碼: readEvent(){wx.getNFCAdapter().startDiscovery({success:(res)>{console.log(--------------start--------)console.log(res);wx.getNFCAdapter().onDiscovered(callback>{console.log(------------onDiscovered----------)console.log(callback)…

問題:【IntelliJ IDEA】解決idea自動聲明變量加finall修飾符問題

問題:【IntelliJ IDEA】解決idea自動聲明變量加finall修飾符問題 場景復現 1 new String() 2 快捷方式生成變量 final修飾的 final String s new String();步驟一&#xff1a;確保settings配置信息 settings-----》Editor------》Code Style--------》java下的這兩個選項不…

echarts 柱狀圖-折線圖-餅圖的基礎使用

上圖示例圖表展示相關配置&#xff1a; var myChart echarts.init(this.$refs.firstMain);myChart.setOption({legend: { // 圖例設置top: "15%",type: "scroll",orient: "vertical",//圖例列表的布局朝向。left: "right",pageIconCo…

安全加密框架圖——Oracle安全開發者

Oracle安全開發者 ACLs 設計 ACLs&#xff08;訪問控制列表&#xff09;時&#xff0c;可以根據以下思路進行設計&#xff1a; 所有者文件權限&#xff1a;確定文件的所有者能夠對文件執行哪些操作&#xff0c;如讀取、寫入、執行等。這可以根據文件的性質和擁有者的職責來決…

k8s集群部署vmalert和prometheusalert實現釘釘告警

先決條件 安裝以下軟件包&#xff1a;git, kubectl, helm, helm-docs&#xff0c;請參閱本教程。 1、安裝 helm wget https://xxx-xx.oss-cn-xxx.aliyuncs.com/helm-v3.8.1-linux-amd64.tar.gz tar xvzf helm-v3.8.1-linux-amd64.tar.gz mv linux-amd64/helm /usr/local/bin…

12 注冊登錄

12 注冊登錄 整體概述 使用數據庫連接池實現服務器訪問數據庫的功能&#xff0c;使用POST請求完成注冊和登錄的校驗工作。 本文內容 介紹同步實現注冊登錄功能&#xff0c;具體涉及到流程圖、載入數據庫表、提取用戶名和密碼、注冊登錄流程與頁面跳轉的代碼實現。 流程圖&a…

六、Linux系統下,文件操作命令都有哪些?

總括&#xff1a; 創建文件/文件夾&#xff1a;touch&#xff1b; 查看&#xff1a;cat/more&#xff1b; 復制&#xff1a;copy&#xff1b; 移動文件/文件夾&#xff1a;mv&#xff1b; 刪除&#xff1a;rm&#xff1b; 1、創建文件 &#xff08;1&#xff09;語法&#x…

docker私有倉庫

# 有個遠程倉庫 &#xff0c;docker官方提供的 ---》我們可以把我們的鏡像傳上去 # 公司做的鏡像&#xff0c;一般不放在遠程倉庫&#xff0c;公司會自己搭建私有倉庫&#xff08;把公司制作的鏡像傳到私有倉庫&#xff09; 1.鏡像傳到官方倉庫 # 第0步&#xff1a;在遠端創建…

阿里云與中國中醫科學院合作,推動中醫藥行業數字化和智能化發展

據相關媒體消息&#xff0c;阿里云與中國中醫科學院的合作旨在推動中醫藥行業的數字化和智能化發展。隨著互聯網的進步和相關政策的支持&#xff0c;中醫藥產業受到了國家的高度關注。這次合作將以“互聯網 中醫藥”為載體&#xff0c;致力于推進中醫藥文化的傳承和創新發展。…

AIGC繪畫:基于Stable Diffusion進行AI繪圖

文章目錄 AIGC深度學習模型繪畫系統stable diffusion簡介stable diffusion應用現狀在線網站云端部署本地部署Stable Diffusion AIGC深度學習模型繪畫系統 stable diffusion簡介 Stable Diffusion是2022年發布的深度學習文本到圖像生成模型&#xff0c;它主要用于根據文本的描述…

UG NX二次開發(C++)-UI Styler中選擇組件或者實體后設置為工作組件

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 文章目錄 1、前言2、在NX2007中創建一個裝配體實例2.1 裝配體模型2.2 欲實現的功能3、創建對話框文件4、在VS2022中創建一個工程項目4.1 創建項目4.1 在hpp中添加頭文件4.2 在cpp中添加代碼4.3 生成dll5、測…