CD46.【C++ Dev】list的模擬實現(1)

目錄

1.STL庫的list

2.模擬實現

節點結構體

list類

無參構造函數

尾插函數

迭代器★

begin()

operator++

前置++

后置++

operator--

前置--

后置--

operator!=

operator==

end()

operator*

const修飾的迭代器的設計


1.STL庫的list

模擬實現list之前,先看看STL庫里的list是怎么做的

STL v3.0版本代碼一覽:

先看鏈表的結構體和構造函數

結構體:

template <class T>
struct __list_node {typedef void* void_pointer;void_pointer next;//后指針void_pointer prev;//前指針T data;//數據域
};

看到next和prev,顯然是雙向鏈表,復習雙向鏈表的參見:

96.【C語言】數據結構之雙向鏈表的初始化,尾插,打印和尾刪
97.【C語言】數據結構之雙向鏈表的頭插,頭刪,查找,中間插入,中間刪除和銷毀函數

CC32.【C++ Cont】靜態實現雙向鏈表及STL庫的list

?構造函數:

list() { empty_initialize(); }//調用空鏈表的構造函數
void empty_initialize() { node = get_node();//調用空間配置器node->next = node;node->prev = node;
}//......
protected:link_type node;

2.模擬實現

定義節點結構體next和prev成員變量,不建議用void_pointer,因為void*需要強制類型轉換,比較麻煩

節點結構體

仿照STL:

namespace mystl
{template<class T>struct __list_node{typedef __list_node<T>* link_type;link_type next;link_type prev;T data;};//......
}

list類

框架:?

template<class T>
class list
{typedef __list_node<T> list_node;
public:
private:
};

發現STL庫中的成員變量只有一個

node為__list_node<T>的指針,顯然是雙向鏈表的哨兵位,如下圖?

照葫蘆畫瓢寫:

template<class T>
class list
{typedef __list_node<T> list_node;typedef __list_node<T>* link_type;
public:
private:link_type node;
};

無參構造函數

生成哨兵位,讓next和prev都指向自己

list()
{node = new list_node;node->next = node;node->prev = node;
}

測試代碼:

#include "list.h"
int main()
{mystl::list<int> ls;return 0;
}

下斷點到return 0,看看無參構造函數是否能正常工作

?可以正常工作

尾插函數

void push_back(const T& x)
{link_type tmp = new list_node;tmp->data = x;//先找尾link_type tail = node->prev;tail->next = tmp;tmp->prev = tail;tmp->next = node;node->prev = tmp;
}

測試代碼:

#include "list.h"
using namespace std;
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);return 0;
}

運行結果:

當然上面的代碼可以簡寫

link_type tmp = new list_node(x);

new list_node(x)會自動調用list_node的構造函數,需要提前準備,將list_node構造函數寫在struct?list_node中即可

struct __list_node
{typedef __list_node<T>* link_type;__list_node(const T& x = T())//寫成缺省參數的形式:next(nullptr), prev(nullptr), data(x){}link_type next;link_type prev;T data;
};

迭代器★

迭代器的本質:自定義類型的封裝

list迭代器不能像模擬vector一樣是指針,因為list不是連續區間,因此迭代器需要重新定義,能讓迭代器++能直接指向下一個節點

因此:vector<int>::iterator和list<int>::iterator從封裝上的格式上來看是一樣的,但底層的實現不一樣

即封裝自定義指針成對象,符合C++面向對象的思想

//it是迭代器,本質上都是調用類的成員函數
it.operator++();
it.operator++(0);
it.operator--();
it.operator--(0);
it.operator*();
it.operator!=(...);
it.operator==(...);

STL庫的解決方法:寫成結構體,存儲節點的指針

struct __list_iterator
{link_type node;
};

?(省略了成員函數和typedef)

再自定義成iterator

typedef __list_iterator<T> iterator;

?可以發現迭代器定義成了實例化的類

注意:__list_iterator定義成類時不要定義到list里面,嵌套類(可參見文章)是有限制的!

template<class T>
struct __list_iterator//是類
{typedef __list_node<T>* link_type;link_type node;
};

?當然list類里面要定義迭代器,這樣利用訪問

begin()

寫在list類中,可以直接構造iterator對象返回

iterator begin()
{//返回哨兵位的下一個節點//或者寫成return node->next;使用隱式類型轉換return iterator(node->next);//構造對象返回
}

當然node->next是自定義類型,需要手動在__list_iterator類中添加構造函數,這個很容易忘

struct __list_iterator
{typedef __list_node<T>* link_type;__list_iterator(link_type x){node = x;}link_type node;
};

或者寫成初始化列表:

__list_iterator(link_type x):node(x)
{}

測試代碼:

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);//::可以訪問typedef的或者訪問內部類mystl::list<int>::iterator it=ls.begin();return 0;
} 

運行結果:

operator++

operator++是__list_iterator類的方法,不能寫在list類中,因為list類中沒有迭代器成員變量

前置++

返回++后的iterator

typedef __list_iterator<T> iterator;
iterator& operator++()
{node= node->next;return *this;
}
后置++

返回++前的iterator

iterator operator++(int)
{iterator tmp(*this);node= node->next;return tmp;
}
operator--

因為是雙向鏈表,所以可以向前和向后移動迭代器

前置--

返回--后的iterator

iterator& operator--()
{node = node->prev;return *this;
}
后置--

返回--前的iterator

iterator& operator--(int)
{iterator tmp(*this);node = node->prev;return tmp;
}
operator!=

注意兩個const修飾

const iterator& x防止權限放大,而且begin()和end()返回的是臨時對象具有常性

operator!=末尾的const是防止修改node

bool operator!=(const iterator& x) const
{return node != x.node;
}
operator==
bool operator==(const iterator& x) const
{return node == x.node;
}
end()

寫在list類中,由于是雙向鏈表,因此返回哨兵位即可

iterator end()
{//返回哨兵位return node;//隱式類型轉換,完整寫法:iterator(node)
}

測試代碼:用迭代器遍歷

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);mystl::list<int>::iterator it=ls.begin();while (it != ls.end()){	std::cout << it.node->data << " ";++it;}return 0;
}

運行結果:

operator*

雖然這里定義的迭代器是實例化的對象,但是迭代器任務是模擬指針行為,因此要有operator*

T& operator*()
{return node->data;
}

?測試代碼

#include <iostream>
#include "list.h"
int main()
{mystl::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);mystl::list<int>::iterator it = ls.begin();std::cout << *it;return 0;
}

注:mystl::list<int>::iterator it = ls.begin();會自動調用默認的拷貝構造,由于__list_iterator的成員變量是自定義類型的指針,淺拷貝沒有問題,而且__list_iterator 不用寫析構函數,節點應該是list類釋放,迭代器只是借助節點訪問

運行結果:

const修飾的迭代器的設計

能這樣寫嗎?

typedef const __list_iterator<T> const_iterator;

不可以,?const修飾的是?__list_iterator<T>這個類,類的成員函數不能被修改

一個簡明的例子說明:

class myclass
{
public:int* node;int data;
};int main()
{const myclass obj;obj.node++;
}

obj.node++是不被允許的,被const修飾的對象的成員變量是不能被修改的

要明確: 無論是否有const修飾,雙向迭代器是要能用operator++和operator--進行修改來訪問的,但const修飾的迭代器指向的內容是不能被修改的,非const修飾的迭代器指向的內容能被修改

(有關const修飾的基礎問題參見38.【C語言】指針(重難點)(C)文章)

那const修飾的迭代器應該模擬類似const T* ptr的情況

在迭代器的成員函數中,只有operator*需要修改,其余都不變

下文將介紹兩種處理方法

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

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

相關文章

數據結構——二叉樹的基本介紹

————————————本文旨在討論與學習計算機知識&#xff0c;歡迎交流————————————上一章&#xff0c;我們講解了樹結構的綜述導論&#xff0c;那么&#xff0c;現在我們來深入了解一下樹結構中最常用研究的結構——二叉樹結構&#xff08;上一章的擴展——…

英偉達發布 Llama Nemotron Nano 4B:專為邊緣 AI 和科研任務優化的高效開源推理模型

英偉達推出了 Llama Nem)otron Nano 4B&#xff0c;這是一款專為在科學任務、編程、符號運算、函數調用和指令執行方面提供強大性能與效率而設計的開源推理模型&#xff0c;其緊湊程度足以支持邊緣部署。該模型僅包含 40 億參數&#xff0c;卻在內部基準測試中實現了比其他多達…

論文閱讀筆記——Autoregressive Image Generation without Vector Quantization

MAR 論文 基于 VQ&#xff08;向量量化&#xff09;的圖像生成方法具有顯著優勢&#xff0c;它通過離散化壓縮將原始圖像映射到有限的 codebook 空間&#xff0c;從而縮小學習范圍、降低建模難度&#xff0c;同時這種離散表示更易于與自回歸&#xff08;AG&#xff09;生成方式…

【科普】關于C 語言日志系統實戰:如何同時輸出到終端和文件?

1.概述 c語言沒有現成的日志庫&#xff0c;如果要記錄日志&#xff0c;需要自己封裝一個日志庫。如果要實現日志級別和參數打印&#xff0c;還是比較麻煩的&#xff0c;正好在github找到了一個c語言開源日志庫&#xff0c;可以實現日志級別打印&#xff0c;參數打印&#xff0…

2025,數字人借直播場景邁過“真假線”丨數智化觀察

作者 | 曾響鈴文 | 響鈴說一夜帶貨超5500萬GMV、觀看人次1300萬&#xff0c;羅永浩數字人在百度電商的直播首秀正在掀起新的行業浪潮——2025&#xff0c;數字人直播帶貨成功出圈&#xff0c;加速進入大眾視野&#xff0c;被更多的消費者所認可。成就這場熱潮的關鍵點之一&…

HTML表格導出為Excel文件的實現方案

1、前端javascript可通過mime類型、blob對象或專業庫&#xff08;如sheetjs&#xff09;實現html表格導出excel&#xff0c;適用于中小型數據量&#xff1b;2、服務器端方案利用后端語言&#xff08;如python的openpyxl、java的apache poi&#xff09;處理復雜報表和大數據&…

企業微信iPad協議端強制拉群漏洞深度分析

正常一次最多邀請40人進群 超過40人的拉群&#xff0c;會變成邀請&#xff0c;需要對方同意 新版本修復了漏洞&#xff0c;但還是可以用老版本進行強制拉群 雖然官方也做了版本過低的限制&#xff0c;但還是有辦法繞過 要么修改版本號或者登錄幾天新版本&#xff0c;之后就可以…

Python編譯器(Pycharm Jupyter)

Pycharm下載不過多贅述pycharm導入anaconda創建的python環境選擇想要的環境 Jupyter Jupyter 是一個開源的交互式計算環境&#xff0c;能夠讓用戶將代碼、文本&#xff08;包括 Markdown&#xff09;、可視化結果等內容整合在一個文檔中&#xff0c;非常適合進行數據分析、科學…

漏洞修復與Fiddler抓包工具的使用

漏洞描述 1. 短信轟炸漏洞 Type:存在三個不同的值。Login是登錄處,register是注冊賬號處的短信驗證碼獲取值,還有一個update值。未注冊的用戶也可以進行發送短信。 2. 手機號繞過,修改密碼漏洞(邏輯漏洞) 目前注冊使用手機號與忘記密碼的手機號驗證測試都可以繞過, …

對象存儲-OSS

目錄 對象存儲背景 阿里云OSS 對象存儲背景 單節點環境下&#xff0c;文件往往存儲在tomcat服務器內&#xff0c;隨著業務需求的增多&#xff0c;單節點已不能滿足需求&#xff0c;項目架構需要擴展到多節點&#xff08;見下圖&#xff09;&#xff0c;此時文…

C語言函數的聲明

1定義&#xff1a;在C語言中&#xff0c;函數是一段具有特定功能的獨立代碼塊&#xff0c;它可以接收輸入參數、執行相關操作并返回結果。2為什么需要函數&#xff08;1&#xff09;代碼復用&#xff1a;避免重復編寫相同功能的代碼&#xff0c; &#xff08;2&#xff09;模塊…

AI人工智能名片小程序源碼系統,名片小程序+分銷商城+AI客服,包含完整搭建教程

智能名片核心功能AI人工智能名片小程序的核心功能設計旨在徹底改變傳統商務交流方式&#xff0c;為用戶提供前所未有的智能化體驗。個性化名片展示是系統的基礎功能&#xff0c;用戶可以通過豐富的模板庫和自定義設計工具&#xff0c;創建獨具特色的電子名片。系統提供多種預設…

React 教程:井字棋游戲

React 教程&#xff1a;井字棋游戲 使用 React 實現一個交互式的井字棋游戲&#xff0c;并配上好看的樣式 // 導入必要的CSS樣式和React庫 import "./App.css"; import { useState } from "react";// Square組件 - 表示棋盤上的一個格子 function Square({…

React源碼2 React中的工廠函數:createRoot()

#React V18.2 源碼前置基礎知識&#xff1a;工廠函數工廠函數是一種設計模式&#xff0c;用于動態創建對象或函數實例。其核心思想是通過封裝對象創建的細節&#xff0c;提供統一的接口&#xff0c;從而增強代碼的靈活性和可維護性&#xff0c;有一些核心作用&#xff1a;解耦創…

《UE5_C++多人TPS完整教程》學習筆記42 ——《P43 瞄準(Aiming)》

本文為B站系列教學視頻 《UE5_C多人TPS完整教程》 —— 《P43 瞄準&#xff08;Aiming&#xff09;》 的學習筆記&#xff0c;該系列教學視頻為計算機工程師、程序員、游戲開發者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; Stephen Ulibarri…

SQL Server 臨時表、表變量與WITH語句的用法與區別

引言 在SQL Server數據處理中,臨時表、表變量和WITH語句(CTE)是關鍵的中間結果集管理工具。臨時表適合大數據量操作,表變量優化小數據量場景,而CTE則簡化復雜查詢邏輯。三者選擇需綜合考量數據量級、事務需求及代碼可讀性。本文將深入解析其工作機制,通過實測對比指導場…

【Android】組件及布局介紹

一&#xff1a;代碼分析 1&#xff1a;Android界面開發方式 &#xff08;1&#xff09;JavaView&#xff08;傳統視圖系統&#xff09; 這是 Android 早期的開發方式&#xff0c;用 Java 或 Kotlin 代碼配合 XML 布局文件 來構建界面。&#xff08;簡單了解即可&#xff09; 分…

Android 音視頻 IPC序列化工具-Flattenable

Android Binder與AIDL與Service使用案例及分析-CSDN博客 講講這個類,被用在Android音視頻中,跨進程序列化反序列化用。與Binder驅動有很強的聯系。位于: feameworks/native/utils/Flattenable.h Flattenable, 譯為令人滿意的。可能是作者十分滿意自己的這些作品吧,起了這…

文獻學習|全面繪制和建模水稻調控組景觀揭示了復雜性狀背后的調控架構。

摘要&#xff1a; 解析調控復雜性狀的機制對于推進作物改良至關重要。在此&#xff0c;我們提出了一個全面的水稻&#xff08;Oryza sativa&#xff09;調控組圖譜&#xff0c;涵蓋了來自三個代表性品種的23種不同組織的染色質可及性。我們的研究揭示了117,176個獨特的開放染色…

Linux的壓縮與解壓縮

一、使用tar命令進行打包與解包 1.0、tar命令簡介和常用選項 tar命令是Linux中經常使用的歸檔工具&#xff0c;它的主要功能是【對文件或者目錄進行打包歸檔】&#xff0c;歸檔為一個文件&#xff0c;但是并不進行壓縮&#xff1b;tar命令的歸檔操作效果如下&#xff1a; tar命…