c++STL-list的模擬實現

c++STL-list的模擬實現

  • list源碼剖析
  • list模擬實現
    • list構造函數
    • 拷貝構造函數
    • 賦值重載
    • 迭代器 iterator
    • 訪問結點數size和判空
    • 尾插 push_back
    • 頭插 push_front
    • 尾刪pop_back
    • 頭刪pop_front
    • 插入 insert
    • 刪除 erase
    • 清空clear和析構函數
    • 訪問結點
  • 參考程序

list源碼剖析

建議先看c++STL-list的使用和迭代器-CSDN博客。

STL中某版本的list的結點原型:

template <class T>
struct __list_node{typedef void* void_pointer;void_pointer next;voie_pointer prev;T data;
}

void 后期還需要強轉。

定義結點用struct,可以換成class,但要另一個類將這個類封裝成友元,因為class默認私有。

__list_node__表示內部的實現,算是項目上的約定。

之后list類的成員:

template <class T, class Alloc = alloc>
class list {
protected:typedef void* void_pointer;//結點類型typedef __list_node<T> list_node;//空間配置器typedef simple_alloc<list_node, Alloc> list_node_allocator;
public://類型typedef T value_type;//類型指針typedef value_type* pointer;typedef const value_type* const_pointer;//類型引用typedef value_type& reference;typedef const value_type& const_reference;typedef list_node* link_type;//結點數和引用數typedef size_t size_type;typedef ptrdiff_t difference_type;//迭代器typedef __list_iterator<T, T&, T*>             iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;//...
protected:link_type node;
}

看代碼(容器)先看構造函數,初始化決定初始結構是什么樣的。

template<class T>
class list {list() { empty_initialize(); }//空結點初始化//證明鏈表在生成時會先//生成哨兵衛結點void empty_initialize() {node = get_node();node->next = node;node->prev = node;}link_type get_node() { return list_node_allocator::allocate(); }link_type create_node(const T& x) {link_type p = get_node();__STL_TRY{//調用定位newconstruct(&p->data, x);}__STL_UNWIND(put_node(p));return p;}void put_node(link_type p) { list_node_allocator::deallocate(p); }iterator begin() { return (link_type)((*node).next); }iterator end() { return node; }
};

allocate是空間配置器,也就是說get_node是獲取一個新的結點。

list的迭代器功能比stringvector復雜,因此庫里的list將迭代器封裝成了一個類,通過模板參數的不同來區分不同類型的迭代器。

//Ref,即reference,引用
//Ptr,即pointer,指針
//表示引用類型和指針類型也作為模板參數的一部分
template<class T, class Ref, class Ptr>
struct __list_iterator {typedef __list_iterator<T, T&, T*>             iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __list_iterator<T, Ref, Ptr>           self;typedef bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef __list_node<T>* link_type;typedef size_t size_type;typedef ptrdiff_t difference_type;link_type node;__list_iterator(link_type x) : node(x) {}__list_iterator() {}__list_iterator(const iterator& x) : node(x.node) {}bool operator==(const self& x) const { return node == x.node; }bool operator!=(const self& x) const { return node != x.node; }reference operator*() const { return (*node).data; }#ifndef __SGI_STL_NO_ARROW_OPERATORpointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */self& operator++() {node = (link_type)((*node).next);return *this;}self operator++(int) {self tmp = *this;++* this;return tmp;}self& operator--() {node = (link_type)((*node).prev);return *this;}self operator--(int) {self tmp = *this;--* this;return tmp;}
};

end()是尾結點的迭代器,begin()end()->next

list模擬實現

list的本質是封裝加運算符重載。

因此list由三部分組成:

  1. 結點類__list_node
  2. 迭代器類__list_iterator
  3. 鏈表本體list

__list_node,考慮到庫中的結點給的前驅和后綴都是void*,正式使用時還要強制轉換,于是這里嘗試做改進:

template<class T>
struct __list_node {//指針域typedef __list_node* pointer;pointer next;pointer view;//數據域T data;
};

為了能做到迭代器重載const修飾和非const修飾的迭代器,參考庫中的__list_iterator,需要設計成三個模板參數的類模板,自己改進了看起來比較冗余的部分:

template<class T, class Ref, class Ptr>
struct __list_iterator {typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __list_iterator<T, Ref, Ptr> self;typedef __list_node<T>* link_node;link_node node;
};

最后是list本體:

class list {
public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __list_node<T> Node;//...
private:Node* node;
};

list構造函數

構造函數選擇這幾個常用的實現:

list ();list (size_t n, const T& val = T());template <class InputIterator>list (InputIterator first, InputIterator last);list (const list& x);

默認構造函數用于生成哨兵衛結點。

要使用list (InputIterator first, InputIterator last);,則需要再加上一個
list (int n, const T& val = T());,防止整型被識別成迭代器。

拷貝構造函數

同樣可以創造新的頭結點,并遍歷鏈表(范圍for)進行尾插。

賦值重載

  • 清理鏈表,保留頭結點,之后遍歷形參的鏈表即可。
  • 同樣可以交換哨兵衛結點。

迭代器 iterator

迭代器用3個模板參數的模板類封裝。

template<class T, class Ref, class Ptr>
struct __list_iterator {typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __list_iterator<T, Ref, Ptr> self;typedef __list_node<T>* link_node;link_node node;
};

迭代器需要支持的操作:

  1. 構造能指向指定結點的構造函數。
  2. 拷貝構造函數。
  3. 解引用操作*,返回迭代器指向的結點的數據域。要求數據域能讀、能寫。
  4. 解引用操作->,返回迭代器指向的結點的數據域,當數據域也是自定義類型時,返回指針。
  5. ==,用于判斷兩個迭代器指向的結點是否相等。
  6. !=,用于判斷兩個迭代器指向的結點是否不等。
  7. ++,當前迭代器指向后繼結點。
  8. --,當前迭代器指向前驅結點。
  9. begin(),返回哨兵衛結點的后一個結點。
  10. end(),返回哨兵衛結點。

訪問結點數size和判空

返回除哨兵衛結點外的結點數_size

判斷_size是否為0,或哨兵衛的兩個指針是否都指向自己。

尾插 push_back

void push_back(const T& val);

end()前插入結點即可。可以另外實現,也可以復用insert

頭插 push_front

void push_front(const T& val);

begin()前插入結點即可。可以另外實現,也可以復用insert

尾刪pop_back

刪除--end()結點即可。

頭刪pop_front

刪除begin()結點即可。

插入 insert

iterator insert(iterator pos, const T& val);

在迭代器pos前插入以val為數據的新結點。
請添加圖片描述

這樣在end()前插入結點相當于是尾插,在begin()前插入結點相當于是頭插。

鏈表的迭代器不受擴容的影響,不會出現迭代器失效的問題,給不給返回值都可以。這里選擇給。

刪除 erase

iterator erase(iterator pos);

刪除pos迭代器指向的結點。

刪除后pos迭代器必定失效,因此需要返回下一個結點的迭代器。

清空clear和析構函數

void clear();

刪除除哨兵衛結點外的所有結點。

析構函數在clear的基礎上,進一步清理哨兵衛結點。

訪問結點

用一個隊首front和隊尾back訪問頭、尾結點即可。

需要注意end()在這里設定為哨兵衛結點,一般情況下不可訪問。

參考程序

某.h文件:

#pragma once
#include<cassert>namespace mystd {template<class Type>void swap(Type& a, Type& b) {Type tmp = a;a = b;b = tmp;}template<class T>struct __list_node {//指針域typedef __list_node* pointer;pointer next;pointer view;//數據域T data;__list_node(const T& x = T()):data(x), next(nullptr), view(nullptr) {}};//三個模板參數分別為:存儲的數據類型//存儲的數據的引用、存儲的數據空間的地址類型template<class T, class Ref, class Ptr>struct __list_iterator {typedef __list_iterator<T, Ref, Ptr> self;typedef __list_node<T>* link_node;link_node node;__list_iterator<T, Ref, Ptr>(link_node x = nullptr):node(x) {}__list_iterator<T, Ref, Ptr>(const self& x): node(x.node) {}Ref operator*() {return node->data;}//為了支持T為自定義類型的情況//返回迭代器指向的結點的數據域的地址Ptr operator->() {return &node->data;}bool operator==(const self& x) const{return node == x.node;}bool operator!=(const self& x) const {return node != x.node;}self& operator++() {node = node->next;return *this;}self& operator--() {node = node->view;return *this;}self operator++(int) {self tmp(*this);node = node->next;return tmp;}self operator--(int) {self tmp(*this);node = node->view;return tmp;}};template<class T>class list {public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __list_node<T> Node;//默認構造函數list<T>() {node = get_node();node->next = node->view = node;_size = 0;}//構造函數list<T>(int n, const T& val = T()) {node = get_node();node->next = node->view = node;size_t tmp = n;for (size_t i = 0; i < tmp; i++)push_back(val);}list<T>(size_t n, const T& val = T()) {node = get_node();node->next = node->view = node;size_t tmp = n;for (size_t i = 0; i < tmp; i++)push_back(val);}template<class Inputiterator>list<T>(Inputiterator first, Inputiterator second) {node = get_node();node->next = node->view = node;while (first != second) {push_back(*first);first++;}}//拷貝構造函數list<T>(const list<T>& obj) {node = get_node();node->next = node->view = node;for (const auto& x : obj)this->push_back(x);}//賦值重載list<T>& operator=(list<T>obj) {mystd::swap(this->node, obj.node);mystd::swap(this->_size, obj._size);return *this;}//析構函數~list() {clear();delete node;}//迭代器iterator begin() {return iterator(node->next);}iterator end() {return iterator(node);}const_iterator begin() const {return const_iterator(node->next);}const_iterator end() const {return const_iterator(node);}//結點數size_t size()const {return _size;}//判斷是否為空bool empty()const {return this->node->next == this->node&& this->node->view == this->node;}//頭插void push_front(const T& val) {insert(begin(), val);}//尾插void push_back(const T& val) {insert(end(), val);}//尾刪void pop_back() {erase(--end());}//頭刪void pop_front() {erase(begin());}//插入iterator insert(iterator pos, const T& val) {Node* cur = pos.node->view;Node* newnode = get_node(val);newnode->next = cur->next;newnode->view = cur;cur->next = newnode;newnode->next->view = newnode;++_size;return iterator(newnode);}//刪除iterator erase(iterator pos) {assert(pos != end());Node* del = pos.node, * cur = pos.node->next;del->view->next = del->next;del->next->view = del->view;delete del;--_size;return iterator(cur);}//清空void clear() {auto it = begin();while (it != end()) {it = erase(it);}}//訪問T& front() {return node->next->data;}T& back() {return node->view->data;}private:Node* get_node(const T& x = T()) {Node* tmp = new Node(x);tmp->next = tmp->view = nullptr;//這里建議賦值tmpreturn tmp;}template<class Type>friend void mystd::swap(Type&, Type&);Node* node;//哨兵衛size_t _size;//結點數};
}

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

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

相關文章

WeakAuras Lua Script ICC (BarneyICC)

WeakAuras Lua Script ICC &#xff08;BarneyICC&#xff09; https://wago.io/BarneyICC/69 全量英文字符串&#xff1a; !WA:2!S33c4TXX5bQv0kobjnnMowYw2YAnDKmPnjnb4ljzl7sqcscl(YaG6HvCbxaSG7AcU76Dxis6uLlHNBIAtBtRCVM00Rnj8Y1M426ZH9XDxstsRDR)UMVCTt0DTzVhTjNASIDAU…

校園網規劃與設計方案

一、項目概述 校園網是學校實現信息化教學、科研與管理的重要基礎設施,其性能與穩定性直接影響學校的整體發展。隨著學校規模不斷擴大、教學科研活動日益豐富,對校園網的帶寬、可靠性、安全性以及智能化管理等方面提出了更高要求。本規劃與設計方案旨在構建一個高速、穩定、…

算法分析:蠻力法

一、實驗目的 1 掌握蠻力法的設計思想(利用計算機去窮舉所有的可能解,再從中依次找出可行解) 2 掌握蠻力法的具體實現和時間復雜度分析 3 理解蠻力法的常見特性 實驗要求&#xff1a;先用偽代碼描述利用蠻力法解決的算法解決方案&#xff0c;再用程序實現&#xff0c;計算時間…

信息系統運行管理員:臨陣磨槍版

信息系統運行管理員考試 - 全覆蓋詳細背誦大綱 (根據考情分析和原始材料&#xff0c;力求完整覆蓋考點細節) 第一部分&#xff1a;基礎知識與運維概覽 Chapter 1: 信息系統運維概述 (上午題 5分) 信息&#xff1a; 含義&#xff1a;香農 - 減少隨機不確定性的東西&#xff1b…

Linux的進程管理和用戶管理

gcc與g的區別 比如有兩個文件&#xff1a;main.c mainc.cpp&#xff08;分別是用C語言和C語言寫的&#xff09;如果要用gcc編譯&#xff1a; gcc -o mainc main.c gcc -o mainc mainc.cpp -lstdc表明使用C標準庫&#xff1b; 區別一&#xff1a; gcc默認只鏈接C庫&#x…

Python 常用模塊(八):logging模塊

目錄 一、引言&#xff1a;日志模塊在項目開發中的重要性二、從 Django 日志配置看 Logging 模塊的核心組成三、logging模塊核心組件詳解3.1 記錄器Logger3.2 級別Level3.3 根記錄器使用3.4 處理器Handler3.5 格式化器Formatter3.6 日志流3.7 日志示例 四、日志模塊總結 一、引…

Servlet原理

Servlet 體系結構的類層次關系 Servlet&#xff08;接口&#xff09;&#xff1a;定義了 Servlet 的核心生命周期方法&#xff08;如 init()、service()、destroy()&#xff09;&#xff0c;是所有 Servlet 的頂層規范&#xff0c;任何 Servlet 都需實現該接口。GenericServlet…

數據科學和機器學習的“看家兵器”——pandas模塊 之五

目錄 4.5 pandas 高級數據處理與分析 一、課程目標 二、對數據表格進行處理 (一)行列轉置 (二)將數據表轉換為樹形結構 三、數據表的拼接 (一)merge () 函數的運用 (二)concat () 函數的運用 (三)append () 函數的運用 四、對數據表格的同級運算 五、計算數據表格中數…

組合問題(去重)

40. 組合總和 II - 力扣&#xff08;LeetCode&#xff09; class Solution { private:vector<vector<int>>result;vector<int>path;void backtracking(vector<int>& candidates, int target,int sum,int startIndex,vector<bool>&used)…

論QT6多線程技術

前言 以前我多線程使用傳統的繼承qthread重寫run()或者繼承qrunable類把對象丟到線程池解決。經過昨天的面試讓我了解到新的技術&#xff0c;我之前看到過只不過沒有詳細的去了解movetotread技術&#xff0c;這個技術是qt5推出的&#xff0c;qt6還在延續使用 代碼結構 以下是…

VTEP是什么

VTEP&#xff08;VXLAN Tunnel Endpoint&#xff0c;VXLAN 隧道端點&#xff09;是 VXLAN&#xff08;Virtual Extensible LAN&#xff09;網絡中的關鍵組件&#xff0c;用于處理 VXLAN 流量的封裝和解封裝。以下以可讀的 Markdown 格式詳細解釋 VTEP 的定義、功能、實現方式以…

antdv3 Tabs.TabPane 右上角增加一個角標Badge

1、Tabs官方說明 Ant Design Vue — An enterprise-class UI components based on Ant Design and Vue.js 2、Badge角標官方效果圖 Ant Design Vue — An enterprise-class UI components based on Ant Design and Vue.js 3、Tabs.TabPane要實現的效果 4、代碼 <Tabs v-m…

淺析 Spring 啟動過程:從源碼到核心方法

淺析 Spring 啟動過程&#xff1a;從源碼到核心方法 一、Spring 注解方式啟動類 Demo二、Spring 啟動過程源碼解析?AnnotationConfigApplicationContext構造函數refresh()方法詳解 三、refresh()的核心方法/步驟obtainFreshBeanFactory() - 獲取Bean工廠prepareBeanFactory(be…

貝葉斯優化Transformer融合支持向量機多變量回歸預測,附相關性氣泡圖、散點密度圖,Matlab實現

貝葉斯優化Transformer融合支持向量機多變量回歸預測&#xff0c;附相關性氣泡圖、散點密度圖&#xff0c;Matlab實現 目錄 貝葉斯優化Transformer融合支持向量機多變量回歸預測&#xff0c;附相關性氣泡圖、散點密度圖&#xff0c;Matlab實現效果一覽基本介紹程序設計參考資料…

智慧化系統安全分析報告

智慧化系統的安全背景與現狀 一、政策法規背景 &#xff08;一&#xff09;全球主要國家/地區政策對比 地區政策名稱核心內容實施時間特點中國《生成式人工智能服務管理暫行辦法》明確服務提供者責任&#xff0c;強調數據合法、隱私保護&#xff0c;禁止生成違法內容2023年8…

【學習筆記】點云自動化聚類簡要總結

聚類是將將具有相似特征劃分為相同點集的操作。 基于空間鄰近性的方法 核心思想&#xff1a;依據點的空間距離進行分組 歐式聚類&#xff08;DBSCAN&#xff0c;KD-tree) 原理&#xff1a;基于半徑搜索和最小點數擴展簇。 優點&#xff1a;適應不規則形狀&#xff0c;無需預…

全志F10c200開發筆記——移植uboot

相關資料&#xff1a; &#xff08;二&#xff09;uboot移植--從零開始自制linux掌上電腦&#xff08;F1C200S)&#xff1c;嵌入式項目&#xff1e;-CSDN博客 F1C200S挖坑日記&#xff08;3&#xff09;——Uboot編譯篇_f1c200s uboot-CSDN博客 一、安裝編譯器 Linaro Rele…

常見WEB漏洞----暴力破解

什么是暴力破解 暴力破解 (Brue Force) 是一種攻擊方法 (窮舉法)&#xff0c;簡稱為“爆破”&#xff0c;黑客通過反復猜解和實驗&#xff0c;旨在以暴力手段登入、訪問目標主機獲取服務&#xff0c;破壞系統安全&#xff0c;其屬于 ATT&CK技術中的一種&#xff0c;常利用…

ARM A64 LDR指令

ARM A64 LDR指令 1 LDR (immediate)1.1 Post-index1.2 Pre-index1.3 Unsigned offset 2 LDR (literal)3 LDR (register)4 其他LDR指令變體4.1 LDRB (immediate)4.1.1 Post-index4.1.2 Pre-index4.1.3 Unsigned offset 4.2 LDRB (register)4.3 LDRH (immediate)4.3.1 Post-index…

2.安卓逆向2-adb指令

免責聲明&#xff1a;內容僅供學習參考&#xff0c;請合法利用知識&#xff0c;禁止進行違法犯罪活動&#xff01; 內容參考于&#xff1a;圖靈Python學院 工具下載&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取碼&#xff1…