C++:list模拟实现

hello,各位小伙伴,本篇文章跟大家一起学习《C++:list模拟实现》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !
如果本篇文章对你有帮助,还请各位点点赞!!!
在这里插入图片描述
话不多说,开始进入正题

🍁list的逻辑结构以及节点代码

在这里插入图片描述

是一个双指针带头链表,所以我选择用一个结构体ListNode来维护节点,如下:

// List的节点类
template<class T>
struct ListNode
{ListNode(const T& val = T()):_val(val),_pPre(nullptr),_pNext(nullptr){}ListNode<T>* _pPre;// 指向前一个结点ListNode<T>* _pNext;// 指向后一个节点T _val;// 该结点的值
};

我对ListNode<T>改一个名字:Node

typedef ListNode<T> Node;
typedef Node* PNode;

🍁list类

🍃私有成员变量_pHead和私有成员函数CreateHead()

private:void CreateHead()// 创建头节点并且初始化{_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;}PNode _pHead;

🍃尾插函数和插入函数

尾插只是插入的其中一种方式,所以实现了插入函数,就能够实现尾插函数。
插入思路图解:在pos位置前插入值为val的节点

创建新节点值为value后;
使prev节点的_pNext指针指向newnode,newnode的节点的_pPre指向prev;
使cur节点的_pPre指针指向newnode,newnode的节点的_pNext指向cur;
最后返回iterator(newnode);

在这里插入图片描述

itearator为迭代器,后面会实现

  • 插入
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{Node* cur = pos._pNode;Node* newnode = new Node(val);Node* prev = cur->_pPre;// prev  newnode  curprev->_pNext = newnode;newnode->_pPre = prev;newnode->_pNext = cur;cur->_pPre = newnode;return iterator(newnode);
}
  • 尾插
void push_back(const T& val)
{insert(end(), val); 
}

🍃构造函数

  • 无参构造
list(const PNode& pHead = nullptr)
{CreateHead();/*_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/
}
  • 带参构造(数值)
list(int n, const T& value = T())
{CreateHead();for (int i = 0; i < n; ++i)push_back(value);
}
  • 带参构造(迭代器)
template <class Iterator>
list(Iterator first, Iterator last)
{CreateHead();while (first != last){push_back(*first);++first;}
}
  • 拷贝构造
list(const list<T>& l)
{CreateHead();// 复用带参构造(迭代器)list<T> temp(l.cbegin(), l.cend());// 与*this的头节点pHead交换指向swap(temp);
}

🍃析构函数

clear()为其中的成员函数,功能:清理list中的数据

~list()
{clear();delete _pHead;_pHead = nullptr;/*Node* cur = _pHead->_pNext;Node* tmp = cur->_pNext;while (cur != _pHead){delete cur;cur = tmp;tmp = tmp->_pNext;}tmp = cur = nullptr;_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/
}

🍃迭代器模拟

逻辑上并不难,也许难理解于模板

//List的迭代器结构体
template<class T, class Ref, class Ptr>
struct ListIterator
{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;ListIterator(PNode pNode = nullptr):_pNode(pNode){}ListIterator(const Self& l){_pNode = l._pNode;}T& operator*(){assert(_pNode != _pNode->_pNext);return _pNode->_val;}T* operator->(){return &(*this);}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){PNode* tmp = _pNode;_pNode = _pNode->_pNext;return tmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){PNode* tmp = _pNode;_pNode = _pNode->_pPre;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}PNode _pNode;
};

这段代码定义了一个模板结构 ListIterator,用于表示List类的迭代器。让我们来解释模板声明部分:

template<class T, class Ref, class Ptr>;

这一行是模板声明,定义了一个模板类 ListIterator,它有三个模板参数:T、Ref 和 Ptr。让我们逐个解释这些参数的作用:

1.T: 这是一个模板参数,表示迭代器指向的元素类型。在使用 ListIterator 时,你需要提供实际的类型作为 T 的值。
2.Ref: 这也是一个模板参数,表示迭代器的引用类型。通常情况下,当你通过迭代器解引用(使用 * 运算符)时,你希望得到的是元素的引用类型。所以 Ref 通常被设定为 T&,表示引用类型为 T 的元素。
3.Ptr: 这是迭代器的指针类型。与 Ref 类似,当你通过迭代器解引用(使用 -> 运算符)时,你希望得到的是元素的指针类型。因此,通常情况下 Ptr 被设定为 T*,表示指针类型为 T 的元素。

通过将这些参数设定为模板参数,ListIterator 类可以适用于不同类型的元素,同时也可以提供不同的引用和指针类型。这样做使得 ListIterator 类更加灵活,能够适用于不同的使用场景。

  • 封装的意义
    将迭代器的实现从 List 类中分离出来,有几个重要的意义和优势:
  1. 模块化设计:通过将迭代器封装为单独的类,可以实现更模块化的设计。这意味着 List 类的实现与迭代器的实现可以分开,每个类都专注于自己的职责。这样的设计使得代码更易于理解、维护和测试。
  2. 可重用性:通过将迭代器设计为独立的类,可以在不同的容器类中重复使用相同的迭代器实现。例如,如果你有另一个类似于 List 的容器类,也需要迭代器来遍历其中的元素,你可以直接重用相同的迭代器实现,而无需重新编写。
  3. 灵活性:将迭代器设计为独立的类使得它们的实现更加灵活。你可以在迭代器类中添加额外的功能或改变迭代器的行为,而不会影响到容器类的实现。这样的设计使得容器和迭代器的职责分离,每个类可以独立地演化和改进。
  4. 通用性:独立的迭代器类可以设计成通用的,适用于多种容器类型。这意味着你可以为不同的容器类实现相同的迭代器接口,使得用户在使用不同的容器时无需学习不同的迭代器接口,提高了代码的一致性和可用性。

总的来说,将迭代器封装为独立的类使得代码更加模块化、可重用、灵活和通用,提高了代码的可维护性、可扩展性和可读性。

🍃list类中迭代器的使用

public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;
  • begin()和end()
// List Iterator
iterator begin()
{return _pHead->_pNext;
}iterator end()
{return _pHead;
}const_iterator begin() const
{return _pHead->_pNext;
}const_iterator end() const
{return _pHead;
}
  • erase
    删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{assert(pos._pNode != _pHead);Node* Prev = pos._pNode->_pPre;Node* Next = pos._pNode->_pNext;delete pos._pNode;Prev->_pNext = Next;Next->_pPre = Prev;return iterator(Next);
}

🍃List Modify

void push_back(const T& val) { insert(end(), val); }
void pop_back() { erase(--end()); }
void push_front(const T& val) 
{ assert(!empty());insert(begin(), val); 
}
void pop_front() { erase(begin()); }

🍁全部代码

#pragma once
#include<assert.h>
#include<iostream>
using namespace std;namespace My_List
{// List的节点类template<class T>struct ListNode{ListNode(const T& val = T()):_val(val),_pPre(nullptr),_pNext(nullptr){}ListNode<T>* _pPre;ListNode<T>* _pNext;T _val;};//List的迭代器类template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T>* PNode;typedef ListIterator<T, Ref, Ptr> Self;ListIterator(PNode pNode = nullptr):_pNode(pNode){}ListIterator(const Self& l){_pNode = l._pNode;}T& operator*(){assert(_pNode != _pNode->_pNext);return _pNode->_val;}T* operator->(){return &(*this);}Self& operator++(){_pNode = _pNode->_pNext;return *this;}Self operator++(int){PNode* tmp = _pNode;_pNode = _pNode->_pNext;return tmp;}Self& operator--(){_pNode = _pNode->_pPre;return *this;}Self& operator--(int){PNode* tmp = _pNode;_pNode = _pNode->_pPre;return tmp;}bool operator!=(const Self& l){return _pNode != l._pNode;}bool operator==(const Self& l){return !(*this != l);}PNode _pNode;};//list类template<class T>class list{typedef ListNode<T> Node;typedef Node* PNode;public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T&> const_iterator;public:///// List的构造list(const PNode& pHead = nullptr){CreateHead();/*_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/}list(int n, const T& value = T()){CreateHead();for (int i = 0; i < n; ++i)push_back(value);/*int cnt = 0;while (cnt < n){PNode _first = new Node(value);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++cnt;}*/}template <class Iterator>list(Iterator first, Iterator last){CreateHead();while (first != last){push_back(*first);++first;}/*while (first != last){PNode _first = new Node(*first);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++first;}*/}list(const list<T>& l){CreateHead();list<T> temp(l.cbegin(), l.cend());swap(temp);/*iterator first = l._pHead->_pNext;iterator last = l._pHead;while (first != last){PNode _first = new Node(*first);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++first;}*/}list<T>& operator=(const list<T> l){CreateHead();swap(l);return *this;/*iterator first = l._pHead->_pNext;iterator last = l._pHead;while (first != last){PNode _first = new Node(*first);PNode tmp = _pHead->_pPre;tmp->_pNext = _first;_first->_pPre = tmp;_first->_pNext = _pHead;_pHead->_pPre = _first;++first;}return *this;*/}~list(){clear();delete _pHead;_pHead = nullptr;/*Node* cur = _pHead->_pNext;Node* tmp = cur->_pNext;while (cur != _pHead){delete cur;cur = tmp;tmp = tmp->_pNext;}tmp = cur = nullptr;_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;*/}///// List Iteratoriterator begin(){return _pHead->_pNext;}iterator end(){return _pHead;}const_iterator begin() const{return _pHead->_pNext;}const_iterator end() const{return _pHead;}///// List Capacitysize_t size()const{Node* cur = _pHead->_pNext;size_t cnt = 0;while (cur != _pHead){++cnt;cur = cur->_pNext;}return cnt;}bool empty()const{return size() == 0;}// List AccessT& front(){return _pHead->_pNext->_val;}const T& front()const{return _pHead->_pNext->_val;}T& back(){return _pHead->_pPre->_val;}const T& back()const{return _pHead->_pPre->_val;}// List Modifyvoid push_back(const T& val) { insert(end(), val); }void pop_back() { erase(--end()); }void push_front(const T& val) { assert(!empty());insert(begin(), val); }void pop_front() { erase(begin()); }// 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){Node* cur = pos._pNode;Node* newnode = new Node(val);Node* prev = cur->_pPre;// prev  newnode  curprev->_pNext = newnode;newnode->_pPre = prev;newnode->_pNext = cur;cur->_pPre = newnode;return iterator(newnode);}// 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){assert(pos._pNode != _pHead);Node* Prev = pos._pNode->_pPre;Node* Next = pos._pNode->_pNext;delete pos._pNode;Prev->_pNext = Next;Next->_pPre = Prev;return iterator(Next);}void clear(){iterator cur = begin();while (cur != end()){cur = erase(cur);}_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;}void swap(list<T>& l){/*list<T> tmp = l;l = *this;*this = tmp;*/PNode tmp = _pHead;_pHead = l._pHead;l._pHead = tmp;}private:void CreateHead(){_pHead = new Node();_pHead->_pNext = _pHead;_pHead->_pPre = _pHead;}PNode _pHead;};
};

你学会了吗?
好啦,本章对于《C++:list模拟实现》的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!

如你喜欢,点点赞就是对我的支持,感谢感谢!!!

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/339455.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue不同页面切换的方式(Vue动态组件)

v-if实现 <!--Calender.vue--> <template><a-calendar v-model:value"value" panelChange"onPanelChange" /></template> <script setup> import { ref } from vue; const value ref(); const onPanelChange (value, mod…

MySQL—函数—数值函数(基础)

一、引言 首先了解一下常见的数值函数哪些&#xff1f;并且直到它们的作用&#xff0c;并且演示这些函数的使用。 二、数值函数 常见的数值函数如下&#xff1a; 注意&#xff1a; 1、ceil(x)、floor(x) &#xff1a;向上、向下取整。 2、mod(x,y)&#xff1a;模运算&#x…

基于Springboot + vue实现的文化民俗网站

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

字节裁员!开启裁员新模式。。

最近&#xff0c;互联网圈不太平&#xff0c;裁员消息此起彼伏。而一向以“狼性文化”著称的字节跳动&#xff0c;却玩起了“低调裁员”&#xff0c;用一种近乎“温柔”的方式&#xff0c;慢慢挤掉“冗余”的员工。 “细水长流”&#xff1a;裁员新模式&#xff1f; 不同于以往…

2024年Google算法更新打击低质量(如AI生成)内容后,英文SEO优化人员该如何调整谷歌SEO优化策略?

3月5日&#xff0c;谷歌发布了2024年的首次算法更新。与以往更新不同&#xff0c;本次更新更加复杂&#xff0c;这次更新旨在提高搜索结果的质量和相关性&#xff0c;可能对外贸网站排名和流量产生显著影响。也将产生更大的网站数据波动。但在担心自己的网站数据受到影响之前&a…

【wiki知识库】04.SpringBoot后端实现电子书的增删改查以及前端界面的展示

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日内容 二、&#x1f30f;前端页面的改造 2.1新增电子书管理页面 2.2新增路由规则 2.3修改the-header代码 三、&#x1f697;SpringBoot后端Ebook模块改造 3.1增加电子书增/改接口 3.1.…

数据挖掘 | 实验三 决策树分类算法

文章目录 一、目的与要求二、实验设备与环境、数据三、实验内容四、实验小结 一、目的与要求 1&#xff09;熟悉决策树的原理&#xff1b; 2&#xff09;熟练使用sklearn库中相关决策树分类算法、预测方法&#xff1b; 3&#xff09;熟悉pydotplus、 GraphViz等库中决策树模型…

盘点2024年还在活跃发版的开源私有网盘项目附源码链接

时不时的会有客户上门咨询&#xff0c;丰盘ECM是不是开源项目&#xff0c;源码在哪里可以下载&#xff1b;如果需要和内部其他系统做集成&#xff0c;购买商业版的话&#xff0c;能否提供源代码做二次开发呢&#xff0c;等等诸多问题。 这里做个统一回复&#xff0c;丰盘ECM产…

Docker安装极简版(三分钟搞定)

什么是Docker? Docker是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 化。容器是…

MLPerf storage基准测试

MLPerf 基准测试 什么是 MLPerf&#xff1f;MLPerf™ 基准测试由来自学术界、研究实验室和行业的 AI 领导者联盟 MLCommons 开发&#xff0c;旨在对硬件、软件和服务的训练和推理性能进行无偏评估。它们都在规定的条件下进行。为了保持在行业趋势的前沿&#xff0c;MLPerf 不断…

0基础认识C语言(理论知识)

为了给0基础一个舒服的学习路径&#xff0c;就有了这个专栏希望带大家一起进步。 话不多说&#xff0c;开始正题。 一、C语言的一段小历史 C语言的设计要追溯到20世纪60年代末和70年代初&#xff0c;在那个时代美国有这么一号人叫做丹尼斯.里奇&#xff0c;他和同事肯.汤普逊…

计算机网络学习实践:DHCP跨网段动态分配IP

计算机网络学习实践&#xff1a;DHCP跨网段动态分配IP 1.实验准备 实验环境&#xff1a;思科的模拟器 实验设备&#xff1a; 1个服务器&#xff0c;2个二层交换机&#xff08;不是三层的&#xff09;&#xff0c;4个PC机&#xff0c;1个路由器 三个网段 192.168.1.0 255.…

一些智能音箱类的软硬件方案

主要参考资料 Rabbit R1: https://www.rabbit.tech/rabbit-r1 mediatek-helio-p35: https://www.mediatek.com/products/smartphones-2/mediatek-helio-p35 NSdisplay: https://www.nsdisplay.com/ai-holobox-mini/ai-holobox-mini.html RK3566: https://www.rock-chips.com/a/…

Java学习Lambda表达式

Lambda表达式 有且只有一个未实现的方法叫做Lambda表达式&#xff0c;可以实现函数式编程 // 这个注解是用来检查你写的函数是否是函数式接口 FunctionalInterfaceinterface Myinterface {int sum(int a, int b);default String priteTitle(String name, int age, String sex)…

ASP+ACCESS酒店预定管理系统

【摘要】宏都大酒店管理信息系统中不能通过互联网方式进行客房预订&#xff0c;通过本次设计主要实现通过互联网方式进行客房预订。让客户足不出户坐在家里就能预订出自己想要的客房。主要功能有&#xff1a;酒店简介、客房简介、客房报价、客房预订信息提交&#xff0c;预订信…

Flutter基础 -- Dart 语言 -- 进阶使用

目录 1. 泛型 generics 1.1 泛型使用 1.2 泛型函数 1.3 构造函数泛型 1.4 泛型限制 2. 异步 async 2.1 异步回调 then 2.2 异步等待 await 2.3 异步返回值 3. 生成器 generate &#xff08;了解&#xff09; 3.1 同步生成器 sync* 使用 sync* 的场景 总结 3.2 异…

关于nodejs单线程

Node是使用C++语言写的一款JavaScrip解析器。 高并发 一般来说,高并发的解决方案就是多线程模型,服务器为每隔客户端请求分配一个线程,使用同步I/o,比如Apache就是这种策略,由于I/O一般都是耗时操作,因为这种策略很难实现高性能,但非常简单,可以实现复杂的交互逻辑。…

Python 的 os 和 shutil 模块

大家好&#xff0c;在日常的编程工作中&#xff0c;处理文件和目录是一个非常常见的任务。无论是创建、复制、移动还是删除文件&#xff0c;这些操作都需要我们与文件系统进行交互。在 Python 中&#xff0c;有两个强大的模块可以帮助我们轻松地进行文件和目录操作&#xff0c;…

Unity协程详解

什么是协程 协程&#xff0c;即Coroutine&#xff08;协同程序&#xff09;&#xff0c;就是开启一段和主程序异步执行的逻辑处理&#xff0c;什么是异步执行&#xff0c;异步执行是指程序的执行并不是按照从上往下执行。如果我们学过c语言&#xff0c;我们应该知道&#xff0…

ctfshow-web入门-信息搜集(web11-web20)

目录 1、web11 2、web12 3、web13 4、web14 5、web15 6、web16 7、web17 8、web18 9、web19 10、web20 1、web11 域名其实也可以隐藏信息&#xff0c;比如flag.ctfshow.com 就隐藏了一条信息 查询域名的 DNS 记录&#xff0c;类型为 TXT&#xff08;域名的说明&#…