C++:模擬實現list及迭代器類模板優化方法

文章目錄

  • 迭代器
  • 模擬實現

本篇模擬實現簡單的list和一些其他注意的點

在這里插入圖片描述

迭代器

如下所示是利用拷貝構造將一個鏈表中的數據挪動到另外一個鏈表中,構造兩個相同的鏈表

list(const list<T>& lt)
{emptyinit();for (auto e : lt){push_back(e);}
}void test_list1()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);list<int> l2(lt);
}

lt作為形參,傳引用可以提高傳參的效率,同時應該加上const修飾來保證不會因為不小心修改了形參導致外部的實參也被修改,這樣的結果是不應該的,因此就要加const把這個形參變成一個const對象

而問題又來了,const對象要使用的是const迭代器,而前面沒有寫const迭代器,因此這里就引入了const迭代器的實現

從vector的模擬實現中,看似似乎只需要在原來的迭代器的基礎上加上一個const即可,但事實上:

const迭代器和普通迭代器是兩種不同的迭代器,不能直接在普通的迭代器后面加const,原因?

要解決這個問題,先重新回顧一下vector中const迭代器的定義流程:

對比vector的迭代器,vector中的迭代器const版本和非const版本直接在非const版本后面加const使它變成const迭代器即可,這樣在調用的時候就可以直接進行調用

在這里插入圖片描述

iterator的定義,const版本就是在指針前面加上const,這樣返回的就是const修飾的指針,因此就可以做到通過該迭代器只讀,不可修改的作用

在這里插入圖片描述

這里的迭代器本質上就是指針在底層進行訪問,然后我們定義一個const指針,使得const指針就不能對指針指向的內容進行修改了

下面仿照vector修改的原理修改list

要修改的部分其實就是下面的代碼:

iterator begin()
{return iterator(_head->_next);
}iterator end()
{return iterator(_head);
}

在函數后加const很簡單,但是核心是要把返回值也定義為const指針版本,這個過程要如何實現?

由于這里是把iterator封裝成了一個類進行的實現,因此需要重新封裝一個類進行實現

	template <class T>struct __list_iterator{typedef list_node<T> Node;typedef  __list_iterator<T> 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;}T& operator*(){return _node->_data;}T* operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};template <class T>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--(){_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;}const T& operator*(){return _node->_data;}const T* operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};

但事實上,這兩份代碼只有很少的地方有區別,更多的內容都是相同的,這樣是不滿足較好的代碼風格,因此在stl源碼中,使用了模板對這兩個類進行了封裝

改進版本如下:

	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& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};template <class T>class list{void emptyinit(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}public:typedef list_node<T> Node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;// 構造函數 list(){emptyinit();}// 拷貝構造list(const list<T>& lt){emptyinit();auto it = lt.begin();//*it = 30;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}// head     tail->prev  tailvoid pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);//        newnode//   prev         curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;// prev cur nextprev->_next = cur->_next;next->_prev = cur->_prev;return iterator(next);}private:Node* _head;size_t _size;};

這里引入了類模板的概念,簡單來說,當需要調用const類型時就會模板實例化出一個const版本的迭代器,再進行相關的操作,這樣的操作可以避免代碼冗余,也是模板的強大之處

模擬實現

#pragma once// 實現的是雙向循環鏈表,鏈表中應該包含節點類和迭代器類,節點類用于從內存中申請節點,迭代器類用于獲取節點指針
namespace mylist
{// 把節點進行封裝,可以動態獲取一個節點template <class T>struct list_node{// 成員list_node<T>* _next;list_node<T>* _prev;T _data;// 成員函數list_node(const T& val = T()):_data(val), _next(nullptr), _prev(nullptr){}};// 對迭代器進行封裝,使得外界看到的是迭代器// 迭代器當中存儲的是某個節點的指針// 可以對迭代器進行各項操作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& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};// 適配器 -- 復用template <class T, class Ref, class Ptr >struct __reverse_iterator{typedef list_node<T> Node;typedef  __reverse_iterator<T, Ref, Ptr> self;// 成員Node* _node;__reverse_iterator(Node* node):_node(node){}self& operator++(){_node = _node->_prev;return *this;}self& operator--(){_node = _node->_next;return *this;}self operator++(int){self tmp(*this);_node = _node->_prev;return tmp;}self operator--(int){self tmp(*this);_node = _node->_next;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator==(const self& pos){return _node == pos._node;}bool operator!=(const self& pos){return !(*this == pos);}};template <class T>class list{void emptyinit(){_head = new Node();_head->_next = _head;_head->_prev = _head;_size = 0;}public:typedef list_node<T> Node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef __reverse_iterator<T, T&, T*> reverse_iterator;typedef __reverse_iterator<T, const T&, const T*> const_reverse_iterator;// 構造函數 list(){emptyinit();}// 拷貝構造list(const list<T>& lt){emptyinit();auto it = lt.begin();//*it = 30;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}// head     tail->prev  tailvoid pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator begin(){return iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator begin() const{return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}reverse_iterator rbegin(){return reverse_iterator(_head->_prev);}reverse_iterator rend(){return reverse_iterator(_head);}const_reverse_iterator rbegin() const{return const_reverse_iterator(_head->_prev);}const_reverse_iterator rend() const{return const_reverse_iterator(_head);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);//        newnode//   prev         curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}iterator erase(iterator pos){Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;// prev cur nextprev->_next = cur->_next;next->_prev = cur->_prev;return iterator(next);}private:Node* _head;size_t _size;};void test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);cout << "正序" << endl;for (auto e : lt){cout << e << " ";}cout << endl;cout << "逆序" << endl;auto rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";rit++;}cout << endl;}
}

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

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

相關文章

運動路徑規劃,ROS發布期望運動軌跡

目錄 一、Python實現&#xff08;推薦方法&#xff09; 1.1代碼cubic_spline_path.py 1.2使用方法 二、C實現 參考博客 想讓機器人/智能車無人駕駛&#xff0c;要有期望路徑&#xff0c;最簡單的是一條直線&#xff0c;或者是一條光滑曲線。 生成路徑的方法有兩種&#xf…

【網絡編程(二)】NIO快速入門

NIO Java NIO 三大核心組件 Buffer&#xff08;緩沖區&#xff09;&#xff1a;每個客戶端連接都會對應一個Buffer&#xff0c;讀寫數據通過緩沖區讀寫。Channel&#xff08;通道&#xff09;&#xff1a;每個channel用于連接Buffer和Selector&#xff0c;通道可以進行雙向讀…

Linux下C++開發

Linux下C開發 Linux 系統介紹 簡介 Linux屬于多用戶多任務操作系統&#xff0c;而Windows屬于單用戶多任務操作系統Linux一切皆文件目錄結構 bin 存儲二進制可執行文件dev 存放的是外接設備&#xff0c;例如磁盤&#xff0c;光盤等。在其中的外接設備是不能直接被使用的&…

Redis數據庫的可視化工具AnotherRedisDesktopManager使用+抖音直播小玩法實踐

一、它是什么 Another Redis DeskTop Manager 是一個開源項目&#xff0c;提供了以可視化的方式管理 Redis 的功能&#xff0c;可供免費下載安裝&#xff0c;也可以在此基礎上進行二次開發&#xff0c;主要特點有&#xff1a; 支持 Windows 平臺和 MacOS 平臺 支持查詢 Key、…

2023-08-17力扣每日一題

鏈接&#xff1a; 1444. 切披薩的方案數 題意&#xff1a; 給定一個矩陣&#xff0c;其中含有多個蘋果&#xff0c;需要切割k-1次,每次可以切割多行/多列&#xff0c;需要保證切割兩個部分都有蘋果&#xff0c;移除靠上/靠右的部分&#xff0c;對留下部分進行后續的切割&…

QT中的按鈕控件Buttons介紹

目錄 Buttons 按鈕控件 1、常用屬性介紹 2、按鈕介紹 2.1QPushButton 普通按鈕 2.2QtoolButton 工具按鈕 2.3Radio Button單選按鈕 2.4CheckButton復選按鈕 2.5Commam Link Button命令鏈接按鈕 2.6Dialog Button Box命令鏈接按鈕 Buttons 按鈕控件 在Qt里&#xff0c;…

Viobot開機指南

0.前言 本篇旨在讓每個拿到Viobot設備的用戶都能夠第一時間測試它的效果&#xff0c;以及將設備配置到自己的環境下面。 1.上電 首先&#xff0c;我們先要把設備接上電源線和網線&#xff0c;最簡單的方式就是網線直連電腦。 電源選用12V1.5A設備自帶的電源即可。 2.配置網…

JavaScript中的this指向,call、apply、bind的簡單實現

JavaScript中的this this是JavaScript中一個特殊關鍵字&#xff0c;用于指代當前執行上下文中的對象。它的難以理解之處就是值不是固定的&#xff0c;是再函數被調用時根據調用場景動態確定的&#xff0c;主要根據函數的調用方式來決定this指向的對象。this 的值在函數被調用時…

深入學習前端開發,掌握HTML、CSS、JavaScript等技術

課程鏈接&#xff1a; 鏈接: https://pan.baidu.com/s/1WECwJ4T8UQfs2FyjUMbxig?pwdi654 提取碼: i654 復制這段內容后打開百度網盤手機App&#xff0c;操作更方便哦 --來自百度網盤超級會員v4的分享 課程介紹&#xff1a; 第1周&#xff1a;HTML5基礎語法與標簽 &#x1f…

web集群學習:搭建 LNMP應用環境

目錄 LNMP的介紹&#xff1a; LNMP組合工作流程&#xff1a; FastCGI介紹&#xff1a; 1、什么是 CGI 2、什么是 FastCGI 配置LNMP 1、部署LNMP環境 2、配置LNMP環境 LNMP的介紹&#xff1a; 隨著 Nginx Web 服務的逐漸流行&#xff0c;又岀現了新的 Web 服務環境組合—…

【Spring Cloud 八】Spring Cloud Gateway網關

gateway網關 系列博客背景一、什么是Spring Cloud Gateway二、為什么要使用Spring Cloud Gateway三、 Spring Cloud Gateway 三大核心概念4.1 Route&#xff08;路由&#xff09;4.2 Predicate&#xff08;斷言&#xff09;4.3 Filter&#xff08;過濾&#xff09; 五、Spring …

如何使用Kali Linux進行密碼破解?

今天我們探討Kali Linux的應用&#xff0c;重點是如何使用它來進行密碼破解。密碼破解是滲透測試中常見的任務&#xff0c;Kali Linux為我們提供了強大的工具來幫助完成這項任務。 1. 密碼破解簡介 密碼破解是一種滲透測試活動&#xff0c;旨在通過不同的方法和工具來破解密碼…

力扣初級算法(數組拆分)

力扣初級算法&#xff08;數組拆分&#xff09; 每日一算法&#xff1a; 力扣初級算法&#xff08;數組拆分&#xff09; 學習內容&#xff1a; 1.問題描述 給定長度為 2n 的整數數組 nums &#xff0c;你的任務是將這些數分成 n 對, 例如 (a1, b1), (a2, b2), …, (an, bn) …

機器人CPP編程基礎-03變量類型Variables Types

機器人CPP編程基礎-02變量Variables 全文AI生成。 C #include<iostream>using namespace std;main() {int a10,b35; // 4 bytescout<<"Value of a : "<<a<<" Address of a : "<<&a <<endl;cout<<"Val…

[Openwrt]一步一步搭建MT7981A uboot、atf、openwrt-21.02開發環境操作說明

安裝ubuntu-18.04 軟件安裝包 ubuntu-18.04-desktop-amd64.iso 修改ubuntu管理員密碼 sudo passwd [sudo] password for w1804: Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully 更新ubuntu源 備份源 sudo cp /etc/apt/so…

CentO7.9安裝Docker

文章目錄 CentO7.9安裝Docker刪除舊版本的Docker安裝Docker倉庫安裝Docker安裝最新版本安裝指定版本 Docker安裝個NGINX查看Docker鏡像運行查看Docker進程查看啟動端口停止Docker容器 CentO7.9安裝Docker 刪除舊版本的Docker sudo yum remove docker \docker-client \docker-…

Vue+ElementUI實現選擇指定行導出Excel

這里記錄一下&#xff0c;今天寫項目時 的一個需求&#xff0c;就是通過復選框選中指定行然后導出表格中選中行的Excel表格 然后這里介紹一個工具箱(模板)&#xff1a;vue-element-admin 將它拉取后&#xff0c;運行就可以看到如下界面&#xff1a; 這里面的很多功能都已經實現…

【NAS群暉drive異地訪問】使用cpolar遠程訪問內網Synology Drive「內網穿透」

文章目錄 前言1.群暉Synology Drive套件的安裝1.1 安裝Synology Drive套件1.2 設置Synology Drive套件1.3 局域網內電腦測試和使用 2.使用cpolar遠程訪問內網Synology Drive2.1 Cpolar云端設置2.2 Cpolar本地設置2.3 測試和使用 3. 結語 前言 群暉作為專業的數據存儲中心&…

jupyter切換conda虛擬環境

環境安裝 conda install nb_conda 進入你想使用的虛擬環境&#xff1a; conda activate your_env_name 在你想使用的conda虛擬環境中&#xff1a; conda install -y jupyter 在虛擬環境中安裝jupyter&#xff1a; conda install -y jupyter 重啟jupyter 此時我們已經把該安裝…

也許你正處于《孤注一擲》中的“團隊”,要留心了

看完這部電影&#xff0c;心情久久不能平靜&#xff0c;想了很多&#xff0c;倒不是擔心自己哪天也成為“消失的yaozi”&#xff0c;而是在想&#xff0c;我們每天所賴以生存的工作&#xff0c;跟電影里他們的工作比&#xff0c;差別在哪里呢&#xff1f; 目錄 1. 產品的本質…