C++学习笔记(17)——list迭代器

系列文章

http://t.csdnimg.cn/u80hL


目录

  • 系列文章
    • @[TOC](目录)
  • 定义
    • 功能
  • 优点
  • 缺点
  • 函数
    • 成员函数
      • insert: 在pos位置插入value(头部和中间插入效率很高)
      • erase:删除指定位置的节点,返回被删除的节点的下一个位置
      • swap:交换两个链表的内容
      • clear:清除链表数据
      • sort:排序
    • 其他函数
      • merge:归并,两个链表归并到一起,小的接到大的后面,要求被归并的链表必须有序
      • assign:拷贝
      • unique:去重
      • remove:删除,删去一个值为data的节点
      • splice:转移,以极高的自由度将一个链表的一部分转移到另一个链表的任意位置(翻译为粘贴,粘接)
    • 流插入
      • 重载—>
      • empty_init( ): 初始化节点
    • 默认构造
      • 无参构造:list()
      • n个value初始化构造
      • 拷贝构造:list(const list<T>& lt)
      • 赋值运算符重载:operator=
      • 析构:~list()
  • 知识点
    • list核心接口:双向迭代器Bidirectional
    • 迭代器的底层
    • debug/release的差异
    • 迭代器的分类
      • 功能上分类
      • 迭代器iterator性质上分类(与容器的底层实现有关系)
      • 迭代器应用点
      • 对于list而言,const有两种形式:
      • const 顺序与修饰

定义

list作为一个容器,它有容器的模板参数和空间配置器;

功能

常数时间在任意位置插入元素

优点

插入非常高效

缺点

链表的遍历不支持下标访问(效率极低),链表只能使用迭代器来实现遍历(C++尽可能少用内部类)

在使用层面,对于链表类可以使用范围for来遍历,但底层是迭代器在起作用(特殊情况下,迭代器的底层就是范围for,具体使用那个取决于编译器的选择)

在实践上,list可以支持[ ]查询,但效率太低因此标准库里没有支持。

函数

经过一段时间的学习我们可以发现各个函数的实现有着功能上的继承关系,及一个函数是另一个函数实现的前提,灵活继承函数的功能我们可以使用较低的代码量就实现较多的功能,接下来我们实现list类将会按照继承的顺序给出函数,因此函数顺序会略显混乱;

成员函数

链表只有front、back允许访问头和尾,没有访问中间节点的运算符重载

insert: 在pos位置插入value(头部和中间插入效率很高)

步骤:

  1. insert函数我们通过参数生成一个新的链表节点;
  2. 再将这个节点接入原链表;
  3. size++;
  4. 最后返回指向插入的节点的迭代器。

list迭代器在insert之后不会有扩容操作,因此它的迭代器不会失效,即list不会有迭代器失效问题

        iterator insert(iterator pos, const T& val) //用含参构造建立一个新节点,这个节点带有val值,它的前后节点与原链表有机结合{//我们生成一个以val为参数的节点PNode newnode = new Node(val); //该节点本身有未定义的前_pPre(nullptr),后 ,我们现在要在下面找到它要被接在哪里// 利用pos迭代器找到我们要找的节点,通过这个节点得到该插入的位置的_pPre,_pNextPNode cur = pos._node;  // 这里我们不用对pos位置的节点数据本身做任何操作,我们要更改它的链表性信息,以它为媒介获取我们要插入的pos位置的前面和后面的节点的链表关系PNode pre = cur->_pPre;//接下来我们把新节点接上去//拼接方法很简单,把头尾位置重置一下即可pre->_pNext = newnode;cur->_pPre = newnode;  //newnode->_pPre = pre;newnode->_pNext = cur;++_size;return iterator(newnode);}

push_back()\bush_front():都使用insert()完成功能。

erase:删除指定位置的节点,返回被删除的节点的下一个位置

删除pos位置的单个节点(删除效率高)
步骤:

  1. 首先记忆将要被删节点和它的前后节点;
  2. 删除被删节点的数据(不用管表示前后节点的变量,那是未实例化的变量,不占用空间);
  3. 将记忆的前后节点相连;
  4. size–;
  5. 返回指向被删节点的下一个节点的迭代器。

erase之后迭代器会失效,因为节点被删除.

        // 删除pos位置的节点,返回该节点的下一个位置iterator erase(iterator pos){//定位并记忆该节点的各个信息PNode _val = pos._node;PNode pPrev = _val->_pPre;PNode pNext = _val->_pNext;//根据以上信息去修改pos位置的节点delete _val;    //核心目标:删除pos位置的节点数据,在此完成//接下来更新节点的链接关系pPrev->_pNext = pNext;  pNext->_pPre = pPrev;--_size;    //大小更新return iterator(pNext); //返回下一节点的位置}

pop_front()\pop_back()都使用erase()完成功能,

swap:交换两个链表的内容

这里取巧了,我们不交换链表内容,我们直接交换链表的头节点地址;

        void swap(list<T>& l)    //交换头节点与大小{std::swap(_pHead, l._pHead);std::swap(_size, l._size);}

clear:清除链表数据

凭借指向链表起点的迭代器,将链表数的所有节点清楚掉,只留下头节点;

        void clear()    //清理数据,要深度清理,需要erase(){iterator it = begin();while (it != end()){it = erase(it);}}

sort:排序

list的sort()函数底层是自身独有的,不同于算法库的sort,它的迭代器是双向迭代器,无法与其他的容器模板兼容;sort()函数排序默认为升序;

list_name.sort();	//sort函数使用方法

想要改变为降序,则:

greater<data_type> gt;
list_name.sort(gt);

或者一步到位:

list_name.sort(greater<data_type> ());	//匿名对象

排序效率
list/vector(release):数据量大时list的排序效率远远大于vector(指数级强大),数据量小则相反。

其他函数

merge:归并,两个链表归并到一起,小的接到大的后面,要求被归并的链表必须有序

assign:拷贝

list2_name.assign(list1_name.begin(),list1_name.end());//将list1拷贝至list2

unique:去重

list_name.unique();

remove:删除,删去一个值为data的节点

list_name.remove(data);

splice:转移,以极高的自由度将一个链表的一部分转移到另一个链表的任意位置(翻译为粘贴,粘接)

例如:
list1:1,2,3,4
list2:10,20,30

eg1.转移全部

iterator1=++list_name1.begin();
list1_name.splice(literator1,list2_name); //将list2转移至list1的尾部
list2_name此时为空。

result:
list1:1,10,20,30,2,3,4
list2(empty)

eg2.转移一个值

list1_name.splice(iterator,list2_name,++list2_name.begin());

result:
list1:1,20,2,3,4
list2:10,30

eg3.转移一个区间

list1_name.splice(iterator,list2_name,list2_name.begin(),list2_name.end());

result:
list1:1,20,30,2,3,4
list2:10

流插入

对于一些自定义类型我们不编写它自己的流插入,我们使用公共的流插入配合解引用即可,防止写死;

重载—>

由于C++全新的命名格式,导致—>在使用过程中不优化就会非常怪异:

  1. 正式写法:iterator.operator—>()—>data_name;
  2. 简化写法:iterator—>—>data_name;

第一个箭头返回对象地址,第二个返回元素地址。
由于正式写法太丑,C++的众多编译器都为其做了特殊处理,只需一个箭头即可调用元素:iterator—>data_name;

empty_init( ): 初始化节点

        void empty_init()   //节点初始化{_pHead = new Node;_pHead->_pPre = _pHead; //空节点头节点的前后节点都指向自己_pHead->_pNext = _pHead;_size = 0;}

默认构造

无参构造:list()

        list()  //空链表的构造函数,其作用大多是声明链表的存在和调用列表函数{empty_init();   //初始化空节点}

n个value初始化构造

        list(int n, const T& value = T())   //新建一个链表,初始化后里面有n个value值节点{empty_init();for (int i = 0; i < n; i++){push_back(value);}}

拷贝构造:list(const list& lt)

逐个节点拷贝(深拷贝)——使用push_back()遍历一遍

如果我们不写拷贝构造,默认给出的构造会浅拷贝,然后一个节点释放两次报错,拷贝要用const迭代器。

        //含参的构造list(const list<T>& l)  //以一个链表为参考,拷贝其内容到一个新链表{empty_init();   for (auto e : l){push_back(e);}}

赋值运算符重载:operator=

        list<T>& operator=( list<T> l)     //将一个链表的值赋给另一个链表{//这里传值l时就已经生成了一个可供调换头节点的链表了swap(l);return *this;}

析构:~list()

        ~list()   //出现问题,编译错误,delete对val实行几次后val的地址就变成乱序,开始报错  {//cout << endl << "~list()" << endl;clear();delete _pHead;  _pHead = nullptr;}

逐个节点释放

知识点

list核心接口:双向迭代器Bidirectional

确认一个容器的节点是不是带头双向循环的方法:看初始化——决定初始结构,结构会显示方向个头的数量;(使用速览定义)

迭代器的底层

迭代器的底层是范围for,编译器会默认使用迭代器处理问题;
不同的迭代器代表且只代表某种访问规律,其本身没有内存实体;
迭代器模拟指针的行为。

debug/release的差异

debug:优化没有全开,递归和循环要很大资源
release:递归和循环影响较小

迭代器的分类

功能上分类

  1. const:正向和反向;
  2. 非const:正向和反向;

迭代器iterator性质上分类(与容器的底层实现有关系)

  1. 单向(++):单链表/哈希表
  2. 双向(++/–):双向链表/红黑树(map/set)
  3. 随机(++/–/+/-):vector/string/deque

迭代器应用点

迭代器提现了封装理念的优越性,封装屏蔽了底层差异和实现的细节,提供了统一的访问修改遍历方式,vector、list、string我们不去关注其中的底层细节,他们的使用方法统一,而底层的实现细节天差地别.

vector使用随机迭代器,它可以使用底层为双向迭代器的函数(类似于权限缩小,随机即可以视为一种特殊的双向,也可以视为一种特殊的单向)
迭代器的底层是范围for

对于list而言,const有两种形式:

  1. 非const形式——iterator,T*,可读可写,权限齐全;
  2. const形式——const_iterator,const T* ,只读,权限只能不变与缩小;

这两种迭代器是以两种类的形式实现的,它们彼此之间没有任何联系,只是概念上相对不同;

迭代器修改数据都是解引用行为。

在日常使用中,如果在使用迭代器之前编写了const iterator组织迭代器本身修改,会锁死迭代器,使其失效。

const 顺序与修饰

  1. const T*——const修饰指向内容;
  2. T* const——const修饰了指针本身;

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

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

相关文章

如何在Java中计算两个日期之间的天数差

在Java开发过程中&#xff0c;我们常常需要处理与日期相关的计算&#xff0c;例如计算两个特定日期之间相隔的天数。Java 8及其后续版本引入了强大的java.time包&#xff0c;提供了丰富的日期时间类和工具&#xff0c;使得这类操作变得简单且精准。本文将详细介绍如何使用java.…

面试算法准备:动态规划

这里写自定义目录标题 1 理论2 例题2.1 斐波那契数列&#xff08;什么是重叠子问题&#xff09;2.1.1 带备忘录的递归解法 2.2 零钱兑换&#xff08;讲解最优子结构&#xff09;2.3 最长递增子序列&#xff08;讲解如何求解状态转移方程&#xff09;2.4 俄罗斯套娃信封问题&…

【Android 开发】模拟器上的/storage/emulated/0 上创建目录

Android创建文件夹失败的原因及解决方法 在Android开发中&#xff0c;经常会遇到创建文件夹的需求&#xff0c;但有时候我们可能会遇到创建文件夹失败的情况。本文将介绍一些常见的原因&#xff0c;并提供相应的解决方法。 常见原因 1.权限问题 Android系统对于文件系统的访…

3月养颜抗氧化市场发展趋势洞察:抗糖亮肤功能性产品成为行业大势

随着我国人口老龄化程度的加深和人们对健康和美丽的追求日益增强&#xff0c;具备养颜抗氧化、抗衰老功能的产品逐渐成为市场热门&#xff0c;备受人们关注。 根据鲸参谋数据显示&#xff0c;今年3月份&#xff0c;在线上电商平台&#xff08;京东天猫淘宝&#xff09;养颜抗氧…

pcba方案开发——血氧仪方案设计

1、方案概述&#xff1a;血氧饱和度&#xff08;SpO2&#xff09;是血液中携带氧分子的氧合血红蛋白(HbO2)的容量占全部血红蛋白(Hb)容量的百分比&#xff0c;即血液中血氧的浓度&#xff0c;是呼吸循环系统的重要生理参数。 血氧被称为心率、血压、体温、呼吸率之后的第五大人…

[Windows] Bypass分流抢票 v1.16.25 五一黄金周自动抢票软件(2024.02.08更新)

五一黄金周要来了&#xff0c;火车票难买到&#xff0c;即便官网候选订票也要看运气&#xff0c;推荐使用这个靠谱的自动抢票软件&#xff0c; 该工具是目前市面上最好用口碑最好的电脑抢票软件&#xff0c;从13年到现在&#xff0c;作者依旧在更新&#xff0c;可以自动识别123…

什么是最优物理隔离文件导出导入解决方案,来看看吧

企业进行物理隔离的主要原因是为了提高安全性&#xff0c;减少安全风险。物理隔离通常指的是将网络或系统中的关键部分与外界断开直接连接&#xff0c;以增强安全性。在企业环境中&#xff0c;这通常意味着将内部网络&#xff08;内网&#xff09;与外部网络&#xff08;如互联…

关于MCU核心板的一些常见问题

BGA植球与焊接&#xff08;多涂焊油&#xff09;&#xff1a; 【BGA芯片是真麻烦&#xff0c;主要是植锡珠太麻烦了&#xff0c;拆一次就得重新植】https://www.bilibili.com/video/BV1vW4y1w7oNvd_source3cc3c07b09206097d0d8b0aefdf07958 / NC电容一般有两种含义&#xff1…

控制台居然可以这么玩?五分钟带你上手ANSI指令,实现一个log工具包

目录 前言 基础知识 进阶实践 ANSI参数 ANSI类 JSLog类 工具的使用说明 配置相关 全局配置项 默认配置 基本用法 打印字符 添加全局配置项 清空所有样式及操作行为 校验传入的参数是否正确 样式控制 Node环境 浏览器中 光标控制指令 光标位置偏移 滚动条控…

python之super

子类在继承父类的时候&#xff0c;一般都会在初始化函数中调用父类的__init__函数&#xff0c;举个例子&#xff1a; class Parent:def __init__(self):print("This is Parent class.")class Child(Parent):def __init__(self):super().__init__()print("This …

XiaodiSec day031 Learn Note 小迪安全学习笔记

XiaodiSec day031 Learn Note 小迪安全学习笔记 记录得比较凌乱&#xff0c;不尽详细 day31 上传漏洞 前置 基础内容在 ctfshow 中演示 中间件 cms 中的文件上传 开始 文件上传一般配合抓包 前台验证, 在前台改就可上传成功 php 后缀的文件有 php 后门&#xff0c;可连…

消费增值:革新你的消费体验,让每一分钱都更有价值

亲爱的顾客们&#xff0c;你们好&#xff01;今天&#xff0c;我想为大家介绍一种革新性的消费模式——消费增值&#xff0c;它赋予每一次购物以额外的价值&#xff0c;让消费过程变得更加丰富多彩。 过去&#xff0c;我们的消费观念往往是“一手交钱&#xff0c;一手交货”&am…

LCD彩屏显示方案选型攻略:从接口到GUI开发工具的全面评估

在现代人类社会&#xff0c;彩色显示技术是科技王国里最为绚丽夺目的技术奇葩&#xff0c;LCD彩屏通过显示实时信息并提供交互式的体验&#xff0c;将信息时代打扮得多姿多彩。无论是智能家电还是医疗健康设备领域&#xff0c;精美直观的LCD彩屏显示&#xff0c;往往能够为用户…

【Linux学习】初始冯诺漫体系结构

文章目录 认识冯诺依曼系统 认识冯诺依曼系统 什么是冯诺依曼体系结构&#xff1f; 冯诺依曼体系结构是一种将程序指令和数据以二进制形式存放在主存储器中&#xff0c;由中央处理器统一控制和执行的计算机系统结构。冯诺依曼体系结构实现了程序的可编程性和硬件与软件的分离&…

wordpress建网站主题案例推荐

wordpress企业网站主题案例 https://www.mymoban.com/wordpress/ wordpress公司官网主题案例 https://www.wowsoho.com/jianzhan wordpress外贸主题案例 https://www.wpniu.com/moban

用户中心 -- 插件使用 插件使用思路

易错注意点 1 5.1启动类 & 入口类 需保持一致 网址&#xff1a; 第一节课&#xff0c;用户管理--后端初始化&#xff0c;项目调通。二次翻工2-CSDN博客 一、 用户管理 框架 网址&#xff1a; 用户管理 --汇总 -- 明细-CSDN博客 1.2 更改路径&#xff0c;并生效 网址…

基于SpringBoot的“家具销售电商平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“家具销售电商平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 管理员登录界面 管理员功能界面 家具分类管理…

【c语言】gcc编译动态库静态库和使用说明

&#xff08;1&#xff09;linux和win下库后缀名 在WIN上封装为.dll&#xff08;动&#xff09;&#xff0c;.lib&#xff08;静&#xff09;。 在LINUX上封装为.so&#xff08;动&#xff09;&#xff0c;.a&#xff08;静&#xff09; &#xff08;2&#xff09;动态库的封…

戴尔g15删掉的数据怎么恢复?介绍几种常用方法

随着科技的发展&#xff0c;电脑已成为我们日常生活和工作中不可或缺的一部分。其中&#xff0c;戴尔G15作为一款高性能的笔记本电脑&#xff0c;受到了许多用户的青睐。然而&#xff0c;就像任何电子设备一样&#xff0c;戴尔G15也难免会遇到数据丢失的问题。因此&#xff0c;…

纳米体育数据足球数据接口: 指数数据包接口文档API示例⑦

纳米体育数据的数据接口通过JSON拉流方式获取200多个国家的体育赛事实时数据或历史数据的编程接口&#xff0c;无请求次数限制&#xff0c;可按需购买&#xff0c;接口稳定高效&#xff1b;覆盖项目包括足球、篮球、网球、电子竞技、奥运等专题、数据内容。 纳米数据API2.0版本…