【C++】STL中list容器内部元素的移动和交换

2023-11-20


前言

提示:list::insert(), list::erase(), list::splice(), std::iter_swap()

list作为C++中的链表容器,相较于vector容器的顺序结构优势在于插入和删除的常数开销。相比于元素这个词,我更喜欢用节点来表示list的独立单元。此篇文章将介绍如何在list内部实现元素(节点)的移动和交换。


提示:以下是本篇文章正文内容,下面案例可供参考

一、list是什么?

list是STL中常用的容器之一,list将元素按顺序储存到链表中,在快速删除和快速插入方面的效率比vector高出许多。STL中的list是一双向链表,具有指向前一节点和后一节点的指针。

二、元素移动

将list中的某一元素(节点)移动到某一位置。

1. 插入 + 删除

list容器提供了

  • insert(pos, beg, end); // 在pos位置插入[beg, end)区间的数据,无返回值
  • erase(pos); // 删除pos位置的数据,返回下一个数据的位置

代码如下(示例):

void printList(const list<int> &l)
{
    for (auto i : l)
        cout << i << " ";

    cout << endl;
}

int main()
{
    list<int> l{1, 2, 3, 4};

    /* 将尾节点移动到头节点位置,即移动后的链表:{4, 1, 2, 3} */
    list<int>::iterator head = l.begin();
    list<int>::iterator tail = next(l.end(), -1);

    // 插入
    l.insert(head, tail, next(tail, 1));
    cout << "The list after insertion: ";
    printList(l);

    // 删除
    l.erase(tail);
    cout << "The list after deletion: ";
    printList(l);
    
	cout << "Iterator head and iterator of 1 in the current list are " << (head == next(l.begin(), 1) ? "" : "not ") << "the same" << endl;
    cout << "Iterator tail and iterator of 4 in the current list are " << (tail == l.begin() ? "" : "not ") << "the same" << endl;

    return 0;
}

输出:

The list after insertion: 4 1 2 3 4
The list after deletion: 4 1 2 3
Iterator head and iterator of 1 in the current list are the same
Iterator tail and iterator of 4 in the current list are not the same

我首先使用insert(pos, beg, end)函数,该函数将指定迭代器范围[beg, end)指向的元素值进行值拷贝,并生成新的元素(节点)然后插入到指定的迭代器pos位置。接下来,使用erase(pos)函数对指定迭代器pos位置进行删除。最后,经过上述操作,我对比了元素值为1和4的迭代器是否还保持一致?可以发现,元素值为4的迭代器因为insert()函数的值拷贝和生成新元素和插入元素,已经不再是原先的元素(节点)迭代器tail了。
这在某些情况下往往不符合开发者对于链表结构移动的操作,因为通常开发者在操作链表移动时,仅仅是将链表的节点进行移动就可以了,所以下面我介绍这种方法。

2. 切除 + 拼接

list容器提供了

  • l1.splice ( iterator l1_pos, list<T,Allocator>& l2, iterator l2_pos ); // 将l2的l2_pos指向元素(节点)切除,拼接到l1的l1_pos处(l1和l2可相同)
    请添加图片描述

代码如下(示例):

int main()
{
    list<int> l{1, 2, 3, 4};

    /* 将尾节点移动到头节点位置,即移动后的链表:{4, 1, 2, 3} */
    list<int>::iterator head = l.begin();
    list<int>::iterator tail = next(l.end(), -1);

    // 切除 + 拼接
    l.splice(head, l, tail);
    cout << "The list after splicing: ";
    printList(l);

    cout << "Iterator head and iterator of 1 in the current list are " << (head == next(l.begin(), 1) ? "" : "not ") << "the same" << endl;
    cout << "Iterator tail and iterator of 4 in the current list are " << (tail == l.begin() ? "" : "not ") << "the same" << endl;

    return 0;
}

输出:

The list after splicing: 4 1 2 3
Iterator head and iterator of 1 in the current list are the same
Iterator tail and iterator of 4 in the current list are the same

从上面的结果不难发现,在经过splice()函数后,元素值为4的节点被移动到了头节点的位置。同时,原先指向1和4元素值的迭代器head和tail依旧指向相同的节点,这非常好的满足了链表移动节点的操作。

三、元素交换

将list中的某两个元素进行交换。

1. 元素值交换

C++ algorithm库中提供了

  • void iter_swap ( Iterator it1, Iterator it2 ); // 用于交换两个迭代器所指向的值

代码如下(示例):

int main()
{
    list<int> l{1, 2, 3, 4};

    /* 将尾节点和头节点进行交换,即交换后的链表:{4, 2, 3, 1} */
    list<int>::iterator head = l.begin();
    list<int>::iterator tail = next(l.end(), -1);

    // 交换元素值
    iter_swap(head, tail);
    cout << "The list after iter_swap: ";
    printList(l);

    cout << "Iterator head and iterator of 1 in the current list are " << (head == next(l.end(), -1) ? "" : "not ") << "the same" << endl;
    cout << "Iterator tail and iterator of 4 in the current list are " << (tail == l.begin() ? "" : "not ") << "the same" << endl;

    return 0;
}

输出:

The list after iter_swap: 4 2 3 1
Iterator head and iterator of 1 in the current list are not the same
Iterator tail and iterator of 4 in the current list are not the same

从上述结果不难看出头元素和尾元素的值的确进行了交换,但可以发现迭代器head不再是当前元素值为1的迭代器,迭代器tail也不再是当前元素值为4的迭代器。
事实上,头尾节点并没有进行交换,实际上交换的则是节点内部的值。这在某些情况下往往不符合链表的交换操作,开发者通常使用的链表交换是将两个节点进行互换,下面我将介绍这种方法。

2. 元素(节点)交换

list容器提供了

  • l1.splice ( iterator l1_pos, list<T,Allocator>& l2, iterator l2_pos ); // 将l2的l2_pos指向元素(节点)切除,拼接到l1的l1_pos处(l1和l2可相同)

代码如下(示例):

int main()
{
    list<int> l{1, 2, 3, 4};

    /* 将尾节点和头节点进行交换,即交换后的链表:{4, 2, 3, 1} */
    list<int>::iterator head = l.begin();
    list<int>::iterator tail = next(l.end(), -1);

    // 交换元素(节点)
    list<int>::iterator it = next(tail, 1);
    
    l.splice(head, l, tail);
    l.splice(it, l, head);
    cout << "The list after swapping nodes: ";
    printList(l);

    cout << "Iterator head and iterator of 1 in the current list are " << (head == next(l.end(), -1) ? "" : "not ") << "the same" << endl;
    cout << "Iterator tail and iterator of 4 in the current list are " << (tail == l.begin() ? "" : "not ") << "the same" << endl;

    return 0;
}

输出:

The list after swapping nodes: 4 2 3 1
Iterator head and iterator of 1 in the current list are the same
Iterator tail and iterator of 4 in the current list are the same

其实,有了上面移动元素的经验,很容易用splice()实现元素的交换,即将两个待交换的节点分别移动到对应位置。


总结

文章简单介绍了list实现元素移动和交换的操作。文章中每种操作提到的2种方法没有谁对谁错,但分别适用于不同的场景。笔者在开发过程中遇到了使用list容器进行常规的链表节点操作,故在此介绍了上面的方法。
希望您能仔细阅读,因为发现和指正文章中的不足之处,是对我莫大的提升,谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++】STL中list容器内部元素的移动和交换 的相关文章

  • 使用 lambda 表达式注册类型

    我想知道如何在 UnityContainer 中实现这样的功能 container RegisterType
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • 适合初学者的良好调试器教程[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有谁知道一个好的初学者教程 在 C 中使用调试器 我感觉自己好像错过了很多 我知道怎么做 单步执行代码并查看局部变量 虽然这常常给我带来问
  • 如何捕获未发送到 stdout 的命令行文本?

    我在项目中使用 LAME 命令行 mp3 编码器 我希望能够看到某人正在使用什么版本 如果我只执行 LAME exe 而不带参数 我会得到 例如 C LAME gt LAME exe LAME 32 bits version 3 98 2
  • 查找进程的完整路径

    我已经编写了 C 控制台应用程序 当我启动应用程序时 不使用cmd 我可以看到它列在任务管理器的进程列表中 现在我需要编写另一个应用程序 在其中我需要查找以前的应用程序是否正在运行 我知道应用程序名称和路径 所以我已将管理对象搜索器查询写入
  • php如何生成动态list()?

    根据我的理解 这就是 list 的工作原理 list A1 A2 A3 array B1 B2 B3 所以在帮助下list 我们可以相应地从数组中分配值 这是我的问题 如何生成动态list 1 基于数据库返回结果 我不确定有多少 但我将其全
  • 如何使用 Castle Windsor 将对象注入到 WCF IErrorHandler 实现中?

    我正在使用 WCF 开发一组服务 该应用程序正在使用 Castle Windsor 进行依赖注入 我添加了一个IErrorHandler通过属性添加到服务的实现 到目前为止一切正常 这IErrorHandler对象 一个名为FaultHan
  • unordered_map 中字符串的 C++ 哈希函数

    看起来 C 标准库中没有字符串的哈希函数 这是真的 在任何 c 编译器上使用字符串作为 unordered map 中的键的工作示例是什么 C STL提供模板专业化 http en cppreference com w cpp string
  • 对 std::vector 进行排序但忽略某个数字

    我有一个std vector
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • 使用 LINQ to SQL 时避免连接超时的最佳实践

    我需要知道在 net 应用程序中使用 LINQ to SQL 时避免连接超时的最佳实践 特别是在返回时IQueryable
  • IQueryable 单元或集成测试

    我有一个 Web api 并且公开了一个端点 如下所示 api 假期 name name 这是 Web api 的控制器 get 方法 public IQueryable
  • 为什么从字典中获取时会得到 Action<> 的克隆?

    我有以下字典 private Dictionary
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • WPF DataGridTemplateColumn 组合框更新所有行

    我有这个 XAML 它从 ItemSource 是枚举的组合框中选择一个值 我使用的教程是 http www c sharpcorner com uploadfile dpatra combobox in datagrid in wpf h
  • 在屏幕上获取字符

    我浏览了 NCurses 函数列表 似乎找不到返回已打印在屏幕上的字符的函数 每个字符单元格中存储的字符是否有可访问的值 如果没有的话Windows终端有类似的功能吗 我想用它来替换屏幕上某个值的所有字符 例如 所有a s 具有不同的特征
  • 使用 pandas 单元格中列表的长度选择行[重复]

    这个问题在这里已经有答案了 我有一张表 df a b c 1 x y x 2 x z c d 3 x t e f g 只是想知道如何使用 c 列的长度选择行 such as df loc len df c gt 1 我知道这是不对的 正确的
  • Objective-C / C 给出枚举默认值

    我在某处读到过关于给枚举默认值的内容 如下所示 typedef enum MarketNavigationTypeNone 0 MarketNavigationTypeHeirachy 1 MarketNavigationTypeMarke
  • 灵气序列解析问题

    我在使用 Spirit Qi 2 4 编写解析器时遇到一些问题 我有一系列键值对以以下格式解析
  • OpenCV SIFT 描述符关键点半径

    我正在深入研究OpenCV的SIFT描述符提取的实现 https github com Itseez opencv blob master modules nonfree src sift cpp 我发现了一些令人费解的代码来获取兴趣点邻域

随机推荐

  • Vue中数组的常用方法

    数组的方法分为变更方法和替换数组 变更方法 push push 方法可向数组的末尾添加一个或多个元素 并返回新的长度 pop pop 方法用于删除数组的最后一个元素并返回删除的元素 改变数组的长度 shift shift 方法用于把数组的第
  • 通过JSP网页连接并读取MySQL数据库中的表

    学习任务要求 配置JDBC使JSP网页能连接MYSQL数据库 用Navicat Premium在MYSQL数据库中建立一张表 在连接好后的JSP网页中显示出MYSQL数据库中的表 前言 在前面 我们已经学习了如何建立 发布和访问JSP网页
  • windows下如何禁止某个特定的应用程序

    windows下如何禁止某个特定的应用程序 最近 想了下如何禁止打开windows下的特定应用程序 查阅资料后终于解决了 下面把具体方法分享给大家 以禁止当前主流游戏 英雄联盟为例 1 win R打开运行栏 输入gpedit msc 2 点
  • 基于SSM框架实现一个用户系统(登录,用户列表,分页,增删改查,用户角色管理功能)

    首先搭建一个Maven工程 配置好Tomcat mybatis等 数据库 tb role tb user user role 这里只给了第一个用户管理员限权 可以对其他用户添加管理员 必须要用第一个用户登录 bean 这三个就不用多说了 直
  • MVC三层架构

    1 MVC三层架构 MVC Model View Controller 是一种常见的软件设计模式 用于组织和管理应用程序的代码和逻辑 它将应用程序分为三个主要部分 模型 Model 视图 View 和控制器 Controller 每个部分都
  • MOS管原理-1

    P型半导体参杂价电子为3的元素 一般为硼 因为硼的价电子比硅少一个 所以在共价键中少了一个电子 留下了空穴 空穴会吸引自由电子过来 入住 所以参与导电的是空穴 N型半导体参杂价电子为5的元素 一般为砷 因为砷的价电子比硅多一个 所以在N型半
  • Java Word转PDF

    两种方式 documents4j groupdocs 一 documents4j 1 添加依赖
  • Springer独立出版

    会议简介 Brief Introduction 2023年触觉与虚拟现实国际会议 ICHVR 2023 会议时间 2023年12月15日 17日 召开地点 中国 北海 大会官网 www ichvr org 2023年触觉与虚拟现实国际会议
  • C++ primer目录

    目录 第1章 快速入门 1 1 编写简单的C 程序 1 2 初窥输入 输出 1 2 1 标准输入与输出对象 1 2 2 一个使用IO库的程序 1 3 关于注释 1 4 控制结构 1 4 1 while语句 1 4 2 for 语句 1 4
  • IT痴汉的工作现状26-好项目,坏项目

    塞翁失马焉知非福 淮南子 人间训 祸兮 福之所倚 福兮 祸之所伏 老子 命运就是这样 当他给你关闭一扇门的同时也为你打开了另一扇门 同样 当他给你打开一扇门的同时也为你关闭了一扇门 有些事情 我们要用辩证的观点去看 人生如此 项目亦如此 伟
  • 数学建模——论文排版

    目录 一 参考文献的排版 1 三种方案 通常使用方案一 方案一有两种方法 2 参考文献排版要点总结 二 附录的排版 具体方法 补充 代码高亮 三 表格标题自动编号 进阶做法 四 公式编辑软件的介绍 1 LaTeX 较难 有时间可学 2 wo
  • AI会议排名_周志华

    AI会议排名 周志华 http blog sina com cn s blog 631a4cc40100xl7d html 南京大学周志华教授写的一个很经典的帖子 不过IJCAI能不能算成是no 1的会议有待商榷 不过总体还算客观 说明 纯
  • Dubbo远程传输协议详解

    前言 上次小编为大家带来了Dubbo调用及容错机制详解 不知道大家有没有去看小编最后留下的问题 欢迎对文章进行评论也希望大家和小编多多交流 今天接着为大家带来Dubbo的内容 传输协议 上次调用机制中并没有涉及Dubbo传输的协议 这次容小
  • 多线程下载文件(支持暂停、取消、断点续传)

    多线程下载文件 支持暂停 取消 断点续传 多线程同时下载文件即 在同一时间内通过多个线程对同一个请求地址发起多个请求 将需要下载的数据分割成多个部分 同时下载 每个线程只负责下载其中的一部分 最后将每一个线程下载的部分组装起来即可 涉及的知
  • 看完这篇 教你玩转渗透测试靶机Vulnhub——HarryPotter:Aragog(1.0.2)

    Vulnhub靶机HarryPotter Aragog渗透测试详解 Vulnhub靶机介绍 Vulnhub靶机下载 Vulnhub靶机安装 Vulnhub靶机漏洞详解 信息收集 漏洞发现 漏洞利用 数据库语句查询 SSH登入 备份文件提权
  • unable to install breakpoint in com... $ $FastClassBySpringCGLIB$ $12fabbfc due to missing line numb

    问题 unable to install breakpoint in com FastClassBySpringCGLIB 12fabbfc due to missing line number attributes Modify comp
  • linux定时执行shell脚本

    一 cron调度进程 c r o n是系统主要的调度进程 可以在无需人工干预的情况下运行作业 有一个叫做 c r o n t a b的命令允许用户提交 编辑或删除相应的作业 每一个用户都可以有一个c r o n t a b文件 来保存调度信
  • 量化投资学习-36:选股的基本方式

    1 选择的总原则 1 强者恒强 热点龙头 2 超跌反弹 星空雷达 2 策略总原则 1 主策略 1 2 辅策略 N 3 候选指标 趋势 支撑线 压力线 短期趋势通道 长期趋势通道 布林线 震荡 MACD底特征 KDJ震荡超卖 9转序列低9 能
  • 4大主流CPU处理器技术架构

    推荐阅读 浅谈linux 内核网络 sk buff 之克隆与复制 深入linux内核架构 进程 线程 了解Docker 依赖的linux内核技术 导读 RISC 精简指令集计算机 是一种执行较少类型计算机指令的微处理器 起源于80年代的MI
  • 【C++】STL中list容器内部元素的移动和交换

    文章目录 前言 一 list是什么 二 元素移动 1 插入 删除 2 切除 拼接 三 元素交换 1 元素值交换 2 元素 节点 交换 总结 前言 提示 list insert list erase list splice std iter