解密list的底层奥秘

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻强烈推荐优质专栏: 🍔🍟🌯C++的世界(持续更新中)
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
金句分享:
✨即使人生还有无数次失望的可能性,✨
✨但我还是想活在理想主义的乌托邦里.✨

目录

  • 一、list底层框架
    • (1) 节点类
    • (2) 迭代器类
    • (3) list类
  • 二、构造函数
    • (1) 无参构造
    • (2) n个value构造
    • (3) 迭代器区间构造
    • (4) 拷贝构造
  • 三、迭代器
    • 迭代器的实现
      • ① 构造
      • ② `*`和`->`
      • ③ 前置++与后置++
      • ④ 前置--与后置--
      • ⑤ 比较运算符
    • list类中的迭代器
    • front和back
  • 四、Modifiers:
    • (1) insert()
    • (2) erase()
    • (3) push_back() 和 push_front()
    • (4) pop_back() 和 pop_front()
    • (5) clear()
    • (6) swap()
  • 结语

本篇通过模拟实现list的构造函数,迭代器,和部分成员函数以帮助大家更加深层的理解list的原理,希望看完这篇文章使得友友们对list有了更加深层的理解.

一、list底层框架

list的底层是一个带头双向循环链表.
在这里插入图片描述

(1) 节点类

因为list中节点可能存储各种类型的值,所以这里使用了一个模板参数T.

list <int>
list<doubel>

 	// List的节点类template<class T>struct list_node{list_node(const T& val = T()):_val(val){}//这里的 T() 表示使用类型 T 的默认构造函数创建一个对象,//它将调用 T 类型的默认构造函数来初始化 val。如果类型 T 没有提供默认构造函数,那么代码将无法编译通过。list_node<T>* _prev=nullptr;	//指向前驱结点list_node<T>* _next=nullptr;	//指向后继结点T _val;							//存储数据};

(2) 迭代器类

很多小伙伴会疑问,为什么一个迭代器类却使用了三个模板参数,是不是有些多余呢?
在这里插入图片描述

其实不然,牛牛依次为大家解释.

  1. class T: 是结点类的存储不同数据所需要使用的模板参数.该模板参数表示要处理的元素的类型。它可以是任意类型,例如整数、浮点数、自定义类等等。在模板实例化时,需要提供一个具体的类型。

  2. Ref: 该模板参数表示指向元素类型 T引用。它定义了对元素的引用类型,在实例化模板时,将使用指定的引用类型来操作元素。

  3. Ptr: 该模板参数表示指向元素类型 T指针。它定义了指向元素的指针类型,在实例化模板时,将使用指定的指针类型来操作元素。

template<class T, class Ref, class Ptr>
意味着
list_iterator<T, const T&, const T*>;

list的迭代器用来遍历链表中的元素,外部通过迭代器的++--进行链表的元素访问,这是一种封装,隐藏内部list的实现细节,外部只能通过迭代器的方式访问.

	//迭代器类template<class T, class Ref, class Ptr>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T, Ref, Ptr> self;//self表示自己list_iterator(Node* node);	//构造list_iterator(const self& list);     //拷贝构造Ref operator*();Ptr operator->();//前置++self& operator++();  //后置++self operator++(int);//前置--self& operator--();//后置--self& operator--(int);bool operator!=(const self& list) const; bool operator==(const self& list);//成员变量Node* _node;};

(3) list类

  template<class T>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;list()//(无参构造)//n个value构造list(int n, const T& value = T());//迭代器区间构造template <class Iterator>list(Iterator first, Iterator last);    //拷贝构造list(const list<T>& list);//各种成员函数/...//析构函数~list();iterator begin();       iterator end();//常属性迭代器const_iterator begin()const;const_iterator end()const; private:Node* _head;size_t _size;};

二、构造函数

对于带头双向循环链表,它的初始化操作是必须的,因为必须创建一个头指针.
在这里插入图片描述
对于list的构造函数,它是很多种方式的,例如:无参构造,nval构造,迭代器区间构造等.
对于每个构造,必须前进行最初的初始化操作,为了避免代码冗余,我们将这个部分单独写成一个初始化操作的函数.

如下:

 void  Init_List(){_head = new Node;	//创建头指针_head->_prev = _head;_head->_next = _head;_size = 0;}

(1) 无参构造

调用Init_List();初始化函数即可.

 list()//初始化很重要(无参构造){Init_List();}

(2) n个value构造

  1. 进行初始化操作.
  2. 尾插nvalue.
	//n个value构造list(int n, const T& value = T()){Init_List();while (n--){push_back(value);}}

(3) 迭代器区间构造

  1. 进行初始化操作.
  2. 利用迭代器的特性,一次将区间中的数据尾插入链表.
//迭代器区间构造template <class Iterator>list(Iterator first, Iterator last){Init_List();while (first != last){push_back(*first);++first;}}

(4) 拷贝构造

链表在物理空间上是不连续的,所以,对于参数是另一个链表的拷贝构造,只能遍历链表进行依次插入数据.

	//拷贝构造list(const list<T>& list){Init_List();auto it = list.begin();while (_size!=list._size){push_back(*it);it++;}}

三、迭代器

迭代器的实现

① 构造

迭代器本质就是一个 Node* _node;结点类的指针.
对于迭代器的构造函数,只需要将结点的地址传过来即可.

list_iterator(Node* node)			//默认构造:_node(node) {}
list_iterator(const self& list)     //拷贝构造:_node(list._node){}

*->

(1) *
*运算符重载,表示对迭代器进行解引用.
使用场景:

list<int>::iterator it = L1.begin();
int start=*it;

很明显,*运算符是需要获取结点所存储的数据.为了减少拷贝以及对数据进行修改,这里采用传引用(Ref )返回.

 Ref operator*() {return _node->_val;//获取该结点的数据}

(2) ->

上面链表中的数据是简单的类型int
在这里插入图片描述

Ptr operator->() {return &_node->_val;// 等价于 return &(_node->_val);}

③ 前置++与后置++

对于链表,迭代器++表示向后访问下一个(后继)结点.学过链表的友友们应该知道.
也就是 _node = _node->_next;

前置++,返回++后的结点的迭代器
后置++,返回++前的结点的迭代器

 //前置++self& operator++() {_node = _node->_next;return *this;}//后置++self operator++(int) {Node* tmp=_node;        //保存++之前的值_node = _node->_next;return tmp;             //返回++之前的值}

④ 前置–与后置–

同理,返回当前结点迭代器的前驱结点.
也就是:_node = _node->_prev;

前置–,返回–后的结点的迭代器
后置–,返回–前的结点的迭代器

 //前置--self& operator--(){_node = _node->_prev;return *this;}//后置--self& operator--(int){Node* tmp = _node;          //保存 -- 之前的值_node = _node->_prev;return tmp;                 //返回 -- 之前的值}

⑤ 比较运算符

比较迭代器是否相等,实际就是比较迭代器所指向的结点是否相等.

 bool operator!=(const self& list) const{return _node != list._node;}bool operator==(const self& list){return _node == list._node;}

list类中的迭代器

在这里插入图片描述

iterator begin(): 返回第一个有效元素位置的迭代器
iterator end(): 返回最后一个有效元素位置的迭代器

	typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin(){return _head->_next;//也可以强转一下//return iterator(_head->_next);}iterator end(){return _head;//也可以强转一下// return iterator(_head);}//常属性迭代器const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}

front和back

在这里插入图片描述

 T& front(){return _head->_next->_val;//返回值}const T& front()const{return _head->_next->_val;}T& back(){return _head->_prev->_val;}const T& back()const{return _head->_prev->_val;}

四、Modifiers:

其实带头双向循环链表的增删改查较于单链表,更加简单,我们画图分析还是很容易实现的.

(1) insert()

在这里插入图片描述
(图片为博主原创,不得随意截图使用)


特殊情况:这是尾插:
在这里插入图片描述(图片为博主原创,不得随意截图使用)


代码示例

 // 在pos位置前插入值为val的节点iterator insert(iterator pos, const T& val){//pos.node  而不是pos->nodeNode* newnode = new Node(val);Node* _prev_node = pos._node->_prev;      //pos位置结点的 原前置 结点Node* _cur_node = pos._node;             //pos位置的结点_prev_node->_next = newnode;newnode->_prev = _prev_node;_cur_node->_prev = newnode;newnode->_next = _cur_node;++_size;//有效数据的个数+1.return newnode;}

(2) erase()

在这里插入图片描述

  // 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){Node* _prev_node = pos._node->_prev;             //pos位置结点的 原前置(prev) 结点Node* _next_node = pos._node->_next;            //pos位置结点的 原后置(next) 结点_next_node->_prev = _prev_node;_prev_node->_next = _next_node;delete pos._node;--_size;return _next_node;}

(3) push_back() 和 push_front()

 //尾插//void push_back(const T& val)//{//    Node* newnode = new Node(val);//    Node* _tail_node = _head->_prev;      // 原尾结点//    _tail_node->_next = newnode;//    newnode->_prev = _tail_node;//    _head->_prev = newnode;//    newnode->_next = _head;//    //    ++_size;//有效数据的个数+1.//}//复用insert更加方便void push_back(const T& val){insert(end(),val);//在头结点前面插入,即为尾插}//头插void push_front(const T& val) { insert(begin(), val);}

(4) pop_back() 和 pop_front()

复用即可,不过多介绍了.

  //尾删void pop_back() { erase(--end()); }//头删void pop_front() { erase(begin()); }

(5) clear()

clear:清除list中的有效数据
遍历链表进行依次删除结点,并将size置为0.

  void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}

(6) swap()

交换两个链表的成员变量即可.

 void swap(list<T>& list){swap(_head, list._head);swap(_size, list._size);}

结语

看完这篇文章,相信大家对list有了更加深层的理解,对于list的迭代器,它并不像前面的stringvector那种原生指针,而是封装成了类,使得链表的迭代器也可以执行++--等操作,因为迭代器类重载了这些运算符.

今天就分享到这里了,如果觉得有帮助的话,可以给牛牛来一个一键三连吗?谢谢支持!
在这里插入图片描述

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

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

相关文章

CDN加速器有哪些?

一、前端使用CDN加速的优缺点 1.CDN优点 (1). 提高网站性能&#xff1a; CDN&#xff08;内容分发网络&#xff09;可以将静态资源&#xff08;如脚本、样式表、图片等&#xff09;缓存在服务器节点上&#xff0c;并通过就近访问用户&#xff0c;从而提供更快的加载速度和更好…

服务器搭建(TCP套接字)-基础版(客户端)

一、socket 1.1、vim man查看socket :!man socket1.2、 依赖的头文件 #include <sys/types.h> #include <sys/socket.h>1.3、原型 int socket(int domain, int type, int protocol);domain说明AF_INETIPV4协议AF_INET6IPV6协议AF_LOCALUnix域协议 type说明S…

GDPU 数据结构 天码行空2

实验内容 用顺序表实现病历信息的管理与查询功能。具体要求如下: 利用教材中定义顺序表类型存储病人病历信息(病历号,姓名&#xff0c;症状)&#xff1b;要求使用头文件。 设计顺序表定位查找算法&#xff0c;写成一个函数&#xff0c;完成的功能为:在线性表L中查找数据元素x…

MATLAB中ilu函数用法

目录 语法 说明 示例 不同类型的不完全 LU 分解 不完全 LU 分解的调降容差 使用 ilu 作为预条件子来求解线性系统 ilu函数的功能是对矩阵进行不完全 LU 分解。 语法 [L,U] ilu(A) [L,U,P] ilu(A) W ilu(A) [___] ilu(A,options) 说明 [L,U] ilu(A) 用零填充执行…

前端框架vBean admin

文章目录 引言I 数据库表设计1.1 用户表1.2 角色表1.3 菜单表II 接口引言 文档:https://doc.vvbin.cn/guide/introduction.html http://doc.vvbin.cn 仓库:https://github.com/vbenjs/vue-vben-admin git clone https://github.com/vbenjs/vue-vben-admin-doc 在线体验demo:…

【前段基础入门之】=>初识 HTML

文章目录 前言HTML的详情简介HTML 发展史HTML 入门1. HTML 标签元素2. HTML标签属性3. HTML的标准结构 总结 前言 在整个前端开发中&#xff0c;必须掌握的技术栈为&#xff1a; HTML &#xff0c;CSS&#xff0c;JavaScript&#xff0c;它们三者&#xff0c;共同组成了前端开发…

JavaEE学习之--类和对象

&#x1f495;粗缯大布裹生涯&#xff0c;腹有诗书气自华&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;Java学习之--类和对象 类和对象 类的实例化&#xff1a; 1.什么叫做类的实例化 利用类创建一个具体的对象就叫做类的实例化&#xff01; 当我们创建了…

简单的手机电脑无线传输方案@固定android生成ftp的IP地址(android@windows)

文章目录 abstractwindows浏览android文件环境准备客户端软件无线网络链接步骤其他方法 手机浏览电脑文件公网局域网everythingpython http.server 高级:固定android设备IP准备检查模块是否生效 windows 访问ftp服务器快捷方式命令行方式双击启动方式普通快捷方式映射新的网络位…

Kindle电子书下载功能关闭怎么办,借助calibre和cpolar搭建私有的网络书库公网访问

Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01; 文章目录 Kindle中国电子书店停运不要慌&#xff0c;十分钟搭建自己的在线书库随时随地看小说&#xff01;1.网络书库软件下载安装2.网络书库服务器设置3.内网穿透工具设置4.公网…

竞赛选题 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别

文章目录 0 前言1 背景2 算法原理2.1 动物识别方法概况2.2 常用的网络模型2.2.1 B-CNN2.2.2 SSD 3 SSD动物目标检测流程4 实现效果5 部分相关代码5.1 数据预处理5.2 构建卷积神经网络5.3 tensorflow计算图可视化5.4 网络模型训练5.5 对猫狗图像进行2分类 6 最后 0 前言 &#…

案例丨如何提升可视化分析能力?听听这两家企业怎么说

神策分析 2.5 版本正式发布经营分析能力以来&#xff0c;已有不少客户接入使用&#xff0c;并充分实现了可视化分析能力的提升。 本文将为大家分享两家客户的真实反馈&#xff0c;希望能够帮助您进一步了解神策经营分析的能力。 案例一&#xff1a;神策数据助力美篇打造公司级“…

基于Python+Pygame实现一个俄罗斯方块小游戏【完整代码】

俄罗斯方块&#xff0c;一款起源于上世纪80年代的经典电子游戏&#xff0c;凭借简单的规则和独特的魅力&#xff0c;一跃成为全球家喻户晓的经典。你知道其实只需要一些基础的编程知识&#xff0c;就可以自己实现它吗&#xff1f;今天&#xff0c;我们将使用Python的Pygame库&a…

第八天:gec6818arm开发板和Ubuntu中安装并且编译移植mysql驱动连接QT执行程序

一、Ubuntu18.04中安装并且编译移植mysql驱动程序连接qt执行程序 1 、安装Mysql sudo apt-get install mysql-serverapt-get isntall mysql-clientsudo apt-get install libmysqlclient-d2、查看是否安装成功&#xff0c;即查看MySQL版本 mysql --version 3、MySQL启动…

有了Spring为什么还需要SpringBoot呢

目录 一、Spring缺点分析 二、什么是Spring Boot 三、Spring Boot的核心功能 3.1 起步依赖 3.2 自动装配 一、Spring缺点分析 1. 配置文件和依赖太多了&#xff01;&#xff01;&#xff01; spring是一个非常优秀的轻量级框架&#xff0c;以IOC&#xff08;控制反转&…

@DateTimeFormat 和 @JsonFormat 的详细研究

关于这两个时间转化注解&#xff0c;先说结论 一、介绍 1、DateTimeFormat DateTimeFormat 并不会根据得到其属性 pattern 把前端传入的数据转换成自己想要的格式&#xff0c;而是将前端的String类型数据封装到Date类型&#xff1b;其次它的 pattern 属性是用来规范前端传入…

python每日一题(模拟用户登录验证)

1、题目 预先设定正确用户名与密码&#xff0c;用来验证用户是否登录成功。 第一次&#xff1a; ① 输入用户名与密码&#xff0c;如果用户名与密码正确&#xff0c;则提示登录成功&#xff1b; ② 如果用户名错误&#xff08;不管密码是否正确&#xff09;&#xff0c;则需要重…

TOGAF架构开发方法—初步阶段

本章描述了满足新企业体系结构业务指令所需的准备和启动活动,包括组织特定体系结构框架的定义和原则的定义。 一、目标 初步阶段的目标是: 确定组织所需的体系结构功能: 审查进行企业架构的组织背景确定受体系结构功能影响的企业组织的元素并确定其范围确定与架构功能相交的…

10分钟设置免费海外远程桌面

前言 本教程将向您介绍如何使用 Amazon Lightsail 服务的免费套餐轻松搭建属于您的远程桌面。依托于 Amazon 全球可用区&#xff0c;您可以在世界各地搭建符合您配置需求的远程桌面。 本教程需要先拥有亚马逊云科技海外账户。现在注册亚马逊云科技账户可以享受12个月免费套餐…

北工大汇编——综合题(2)

题目要求 编写一个比赛得分程序。共有7 个评委&#xff0c;按百分制打分&#xff0c;计分 原则是去掉一个最高分和一个最低分&#xff0c;求平均值。要求&#xff1a; 评委的打分以十进制从键盘输入。成绩以十进制给出&#xff0c;并保留 1位小数。输入输出时屏幕上要有相应提…

基于海康Ehome/ISUP接入到LiveNVR实现海康摄像头、录像机视频统一汇聚,做到物联网无插件直播回放和控制

LiveNVR支持海康NVR摄像头通EHOME接入ISUP接入LiveNVR分发视频流或是转GB28181 1、海康 ISUP 接入配置2、海康设备接入2.1、海康EHOME接入配置示例2.2、海康ISUP接入配置示例 3、通道配置3.1、直播流接入类型 海康ISUP3.2、海康 ISUP 设备ID3.3、启用保存3.4、接入成功 4、相关…