【C++】list
list
- 1. 简单了解list
- 2. list的常见接口
- 3. 简单实现list
- 4. vector和list比较
1. 简单了解list
- list的底层是带头双向循环列表。
- 因此list支持任意位置的插入和删除,且效率较高。但其缺陷也很明显,由于各节点在物理空间是不连续的,所以不支持对任意位置的访问,效率低。
- list的迭代器底层不仅仅是指针这么简单,因为其迭代器支持前后双向迭代,而其空间又不连续,所以其底层是对指针的封装。(后面讲)
2. list的常见接口
- 构造

例子

- 普通迭代器

与其他容器的迭代器一样,只不过list的底层实现更加复杂,现在暂且将其看成指针。
例子
//迭代器
void test3()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);auto it = lt.begin();while (it != lt.end()){cout << *it << " ";++it;}cout << endl;
}
//运行结果:
//1 2 3 4
- 头插头删和尾插尾删
例子
void test2()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);for (auto e : lt){cout << e << " ";}cout << endl;lt.pop_back();lt.pop_back();lt.pop_front();lt.pop_front();lt.push_front(4);lt.push_front(3);lt.push_front(2);lt.push_front(1);for (auto e : lt){cout << e << " ";}cout << endl;
}
//运行结果:
//1 2 3 4
//1 2 3 4
- 插入

例子
void test3()
{list<int> lt;lt.push_back(1);lt.push_back(3);lt.push_back(4);//想在第二个位置插入2,怎么做//lt.insert(lt.begin()+1,2);//错误的,list的iterator没有重载+。这个等下讲原因。auto it = lt.begin();++it;lt.insert(it, 2);for (auto e : lt){cout << e << " ";}cout << endl;
}
//运行结果:
//1 2 3 4
这样确定插入位置太麻烦了,可以用find查找。
auto it = find(lt.begin(),lt.end(),3);
if (it != lt.end())
{lt.insert(it,2);
}
- 删除

例子
//删除偶数//删除后,迭代器还指向被删除空间,存在迭代器失效问题//所以要重新赋值it = lt.begin();while (it != lt.end()){if (*it % 2 == 0){it = lt.erase(it);}else{++it;}}
- front和back

例子

- 逆置和排序


例子
void test5()
{list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.reverse();for (auto e : lt){cout << e << " ";}cout << endl;lt.sort();for (auto e : lt){cout << e << " ";}cout << endl;
}
//运行结果
//4 3 2 1
//1 2 3 4
拓展
(1)库里也有sort,为什么还要在list再写一个?C++库的sort不能用。
(2)这涉及到迭代器的分类。从功能上,由容器底层结构决定,迭代器有单项迭代器、双向迭代器和随机迭代器。单项迭代器只能++,向后迭代,例如forward_list/unordered_xxx的迭代器;双向迭代器能++/–,例如list/map/set;随机迭代器能+/-/++/–,例如string/vector/deque。
(3)有随机迭代器的容器能用随机的、双向的、单向的迭代器的库函数,有双向迭代器的容器能用双向的、单向的迭代器的库函数。
(4)list的迭代器类型是双向的,库函数sort的迭代器类型是随机的,所以list的数据排序不能用库函数sort。


- 归并

例子
void test6()
{list<int> lt1;lt1.push_back(1);lt1.push_back(3);lt1.push_back(5);lt1.push_back(7);list<int>lt2;lt2.push_back(2);lt2.push_back(4);lt2.push_back(6);lt2.push_back(8);lt1.merge(lt2);for (auto e : lt1){cout << e << " ";}cout << endl;cout << "lt1的大小为:" << lt1.size() << endl;cout << "lt2是否变为空:" << lt2.empty() << endl;
}

- unique

例子
list<int> lt1;lt1.push_back(1);lt1.push_back(1);lt1.push_back(2);lt1.push_back(2);lt1.unique();cout << "lt1的大小:" << lt1.size() << endl;for (auto e : lt1){cout << e << " ";}cout << endl;

- remove

list<int> lt1;lt1.push_back(1);lt1.push_back(1);lt1.push_back(2);lt1.push_back(2);lt1.remove(1);//相当于find+erasecout << "lt1的大小:" << lt1.size() << endl;for (auto e : lt1){cout << e << " ";}cout << endl;

remove不像erase,它的参数是值而不是迭代器,且remove如果要移除的值不存在,不会报错。
- splice

list<int> lt1;lt1.push_back(1);lt1.push_back(2);lt1.push_back(3);lt1.push_back(4);list<int> lt2;lt2.push_back(5);lt2.push_back(6);lt2.push_back(7);lt2.push_back(8);lt1.splice(lt1.begin(), lt2);//将lt2的所有节点全部转移到lt1之前lt1.splice(lt1.begin(), lt2,--lt2.end());//将lt2的最后一个元素转移到lt1之前lt1.splice(lt1.begin(), lt2, ++lt2.begin(), lt2.end());//将迭代器区间的节点转移到lt1之前lt1.splice(lt1.begin(), lt1, ++lt1.begin(), lt1.end());//将lt1第一个节点后面的节点转移到lt1之前for (auto e : lt1){cout << e << " ";}cout << endl;
3. 简单实现list
#include<iostream>
using namespace std;namespace zn
{//节点template<class T>struct ListNode{ListNode<T>* _prev;ListNode<T>* _next;T _val;ListNode(const T& val = T()):_prev(nullptr), _next(nullptr), _val(val){}};//迭代器(双向迭代器)//迭代器底层都是指针,但有些指针需要封装,例如节点的指针,不然不能满足++/--等操作template<class T, class Ref, class Ptr>//T == T, Ref == T&/const T&, Ptr == T*/const T*struct __list_iterator{typedef ListNode<T>* iterator;typedef __list_iterator<T, Ref, Ptr> This;iterator _node;//构造__list_iterator(iterator node):_node(node){}//*重载Ref operator*(){return _node->_val;}//->重载//如果T恰好是结构体类型,而迭代器又被看成指针,那么->就可以派上用场Ptr operator->(){return &(_node->_val);}//++重载This& operator++(){_node = _node->_next;return *this;}This operator++(int){This tmp(_node);_node = _node->_next;return tmp;}//--重载This& operator--(){_node = _node->_prev;return *this;}This operator--(int){This tmp(_node);_node = _node->_prev;return tmp;}//==重载和!=重载bool operator==(__list_iterator lit)const{return _node == lit._node;}bool operator!=(__list_iterator lit)const{return !(_node == lit._node);}};//反向迭代器//对正向迭代器的封装,从而得到我们想要的操作template<class T,class Ref,class Ptr>class ReverseIterator{typedef __list_iterator<T, Ref, Ptr> iterator;typedef ReverseIterator<T, Ref, Ptr> reverse_iterator;iterator _it;ReverseIterator(iterator it):_it(it){}public:Ref operator*(){iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}reverse_iterator& operator++(){--_it;return *this;}reverse_iterator operator++(int){reverse_iterator tmp = *this;--_it;return tmp;}reverse_iterator& operator--(){++_it;return *this;}reverse_iterator operator--(int){reverse_iterator tmp = *this;++_it;return tmp;}bool operator!=(const reverse_iterator& rit){return _it != rit._it;}bool operator==(const reverse_iterator& rit){return _it == rit._it;}};//listtemplate<class T>class list{typedef ListNode<T> Node;typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef ReverseIterator<T, T&, T*> reverse_iterator;typedef ReverseIterator<T, const T&, const T*> const_reverse_iterator;public://构造list(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}//拷贝构造list(const list<T>& lt)//list(const list& lt){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;for (auto& e : lt){push_back(e);}_size = lt._size;}//交换void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}//=重载list<T> operator=(list<T> lt){swap(lt);return *this;}//析构~list(){Node* cur = _head->_prev;while (cur != _head){Node* tmp = cur->_next;delete cur;cur = tmp;}delete _head;_head = nullptr;}//迭代器iterator begin(){return _head->_next;}const_iterator begin()const{return _head->_next;}iterator end(){return _head;}const_iterator end()const{return _head;}reverse_iterator rbegin(){return reverse_iterator(end());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rend()const{return const_reverse_iterator(begin());}//插入(默认在pos前插入)iterator insert(iterator pos, const T& val){Node* newnode = new Node(val);Node* cur = pos._node;Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;cur->_prev = newnode;newnode->_next = cur;++_size;//隐式类型转换//返回指针类型,然后用类类型接收,会调用构造return newnode;}//删除iterator earse(iterator pos){//头节点不能删除,否则析构时会报错assert(pos != end());Node* cur = pos->_node;Node* prev = cur->_prev;Node* next = cur->_next;prev->_next = next;next->_prev = prev;delete cur;--_size;return next;}//尾插和尾删void push_back(const T& val){insert(end(), val);}void pop_back(){erase(--end());}//头插和头删void push_front(const T& val){insert(begin(), val);}void pop_front(){erase(begin());}//大小size_t size(){return _size;}//清理void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}private://指向头节点Node* _head;size_t _size;};void test_iterator(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);auto it = lt.begin();while (it != lt.end()){cout << *it << " ";it++;}cout << endl;}
}
4. vector和list比较
| vector | list | |
|---|---|---|
| 底层 | 顺序表,可扩容 | 双向循环链表,带头节点 |
| 效率 | 具有连续的空间,空间利用率高;访问元素效率高,支持随机访问;插入和删除元素效率低,需要挪动元素,时间复杂度为O(N) | 底层开辟节点,空间利用率低;访问元素效率低,不支持随机访问; 插入和删除元素效率高,时间复杂度为O(1) |
| 迭代器 | 是原生态指针;是随机迭代器,支持+/-等操作;无论是插入还是删除,都会导致迭代器失效(插入需要扩容,扩容后原来的迭代器失效) | 是对原生态指针的封装;是双向迭代器,不支持+/-等操作 ;删除会导致迭代器失效 |
| 应用 | 适用于插入和删除操作少,访问多的情况 | 适用于插入和删除操作多,访问少的情况 |
相关文章:
【C++】list
list 1. 简单了解list2. list的常见接口3. 简单实现list4. vector和list比较 1. 简单了解list list的底层是带头双向循环列表。因此list支持任意位置的插入和删除,且效率较高。但其缺陷也很明显,由于各节点在物理空间是不连续的,所以不支持对…...
剪枝基础与实战(2): L1和L2正则化及BatchNormalization讲解
1. CIFAR10 数据集 CIFAR10 是深度学习入门最先接触到的数据集之一,主要用于图像分类任务中,该数据集总共有10个类别。 图片数量:6w 张图片宽高:32x32图片类别:10Trainset: 5w 张,5 个训练块Testset: 1w 张,1 个测试块Pytorch 集成了很多常见数据集的API, 可以通过py…...
C语言学习笔记---指针进阶01
C语言程序设计笔记---016 C语言指针进阶前篇1、字符指针2、指针数组2.1、指针数组例程1 -- 模拟一个二维数组2.2、指针数组例程2 3、数组指针3.1、回顾数组名?3.2、数组指针定义与初始化(格式)3.3、数组指针的作用 --- 常用于二维数组3.4、数…...
【Go 基础篇】Go 语言字符串函数详解:处理字符串进阶
大家好!继续我们关于Go语言中字符串函数的探索。字符串是编程中常用的数据类型,而Go语言为我们提供了一系列实用的字符串函数,方便我们进行各种操作,如查找、截取、替换等。在上一篇博客的基础上,我们将继续介绍更多字…...
GAN原理 代码解读
模型架构 代码 数据准备 import os import time import matplotlib.pyplot as plt import numpy as np import torchvision.transforms as transforms from torch.utils.data import DataLoader from torchvision import datasets import torch.nn as nn import torch# 创建文…...
HTML的label标签有什么用?
当你想要将表单元素(如输入框、复选框、单选按钮等)与其描述文本关联起来,以便提供更好的用户界面和可访问性时,就可以使用HTML中的<label>标签。<label>标签用于为表单元素提供标签或标识,使用户能够更清…...
docker在阿里云上的镜像仓库管理
目录 一.登录进入阿里云网站,点击个人实例进行创建 二.创建仓库,填写相关信息 三.在访问凭证中设置固定密码用于登录,登录时用户名是使用你注册阿里云的账号名称,密码使用设置的固定密码 四.为镜像打标签并推送到仓库 五.拉取…...
html-dom核心内容--四要素
1、结构 HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。 2、核心关注的内容:“元素”,“属性”,“修改样式”,“事件反应”。>四要素…...
golang的继承
golang中并没有继承以及oop,但是我们可以通过struct嵌套来完成这个操作。 定义struct 以下定义了一个Person结构体,这个结构体有Eat方法以及三个属性 type Person struct {Name stringAge uint16Phone string }func (recv *Person) Eat() {fmt.Prin…...
Google Play商店优化排名因素之应用截图与视频
屏幕截图是影响转化率的最重要的视觉效果之一。大多数人只需查看应用程序屏幕截图,就会决定是否尝试去下载我们的应用程序。 1、在Google Play商店中,搜索结果页面根据我们搜索的关键词有不同的样式。 展示应用程序中最好的部分,添加一些文字…...
fastadmin iis伪静态应用入口文件index.php
<?xml version"1.0" encoding"UTF-8"?> <configuration><system.webServer><rewrite><rules><rule name"OrgPage" stopProcessing"true"><match url"^(.*)$" /><conditions…...
0821|C++day1 初步认识C++
一、思维导图 二、知识点回顾 【1】QT软件的使用 1)创建文件 创建文件时,文件的路径一定是全英文 2)修改编码 工具--->选项--->行为--->默认编码:system 【2】C和C的区别 C又叫C plus plus,C是对C的扩充&…...
Linux上实现分片压缩及解压分片zip压缩包 - 及zip、unzip命令详解
👨🎓博主简介 🏅云计算领域优质创作者 🏅华为云开发者社区专家博主 🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入! 🐋 希望大家多多支…...
概率论作业啊啊啊
1 数据位置 (Measures of location) 对于数据集: 7 , 9 , 9 , 10 , 10 , 11 , 11 , 12 , 12 , 12 , 13 , 14 , 14 , 15 , 16 7,9,9,10,10,11,11,12,12,12,13,14,14,15,16 7,9,9,10,10,11,11,12,12,12,13,14,14,15,16 计算加权平均数,其中权重为: 2 , 1 , 3 , 2 ,…...
React re-render
What is? react的渲染分为两个阶段: render,组件第一次出现在屏幕上的时候触发re-render, 组件第一次渲染之后的渲染 当app的数据更新时(用户手动更新、或异步请求)。 When? re-render发生有四种可能: state改变…...
从零开始配置Jenkins与GitLab集成:一步步实现持续集成
在软件开发中,持续集成是确保高效协作和可靠交付的核心实践。以下是在CentOS上安装配置Jenkins与GitLab集成的详细步骤: 1.安装JDK 解压JDK安装包并设置环境变量: JDK下载网址 Java Downloads | Oracle 台灣 tar zxvf jdk-11.0.5_linux-x64_b…...
高效多用的群集-Haproxy搭建Web集群
Haproxy搭建 Web 群集 一、Haproxy前言 HAProxy是一个使用c语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TcP和HrrP的应用程序代理。HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。…...
aws的s3匿名公开访问
点击桶权限 ,添加策略 {"Version": "2012-10-17","Statement": [{"Sid": "AddPerm","Effect": "Allow","Principal": "*","Action": "s3:GetObject&qu…...
2023科隆游戏展:虚幻5游戏百花齐放,云渲染助力虚幻5高速渲染
8月23日,欧洲权威级游戏展示会——科隆游戏展拉开帷幕。今年的参展游戏也相当给力,数十款游戏新预告片在展会上公布,其中有不少游戏使用虚幻5引擎制作,开创了游戏开发新纪元。 虚幻5游戏百花齐放,渲染堪比电影级效果 …...
Spark大数据分析与实战笔记(第一章 Scala语言基础-2)
文章目录 章节概要1.2 Scala的基础语法1.2.1 声明值和变量1.2.2 数据类型1.2.3 算术和操作符重载1.2.4 控制结构语句1.2.5 方法和函数 章节概要 Spark是专为大规模数据处理而设计的快速通用的计算引擎,它是由Scala语言开发实现的,关于大数据技术…...
3倍效率的磁盘清理工具:Czkawka如何让存储空间管理变得简单
3倍效率的磁盘清理工具:Czkawka如何让存储空间管理变得简单 【免费下载链接】czkawka 一款跨平台的重复文件查找工具,可用于清理硬盘中的重复文件、相似图片、零字节文件等。它以高效、易用为特点,帮助用户释放存储空间。 项目地址: https:…...
字节Agent开发岗面试血泪史:ReAct框架、IterResearch架构、训练流程全解析,小白必看!收藏!
字节Agent开发岗面试血泪史:ReAct框架、IterResearch架构、训练流程全解析,小白必看!收藏! 文章通过字节Agent开发岗校招面试实例,揭示候选人因缺乏底层逻辑和工程实现细节而失败。详细解析ReAct框架、IterResearch架构…...
告别手点!用SAM-Veteran这个MLLM智能体,让AI像老手一样自动分割图片
告别手点!用SAM-Veteran这个MLLM智能体,让AI像老手一样自动分割图片 在图像处理领域,分割任务一直是计算机视觉的核心挑战之一。无论是电商平台的商品抠图、医疗影像的病灶标注,还是自动驾驶中的场景理解,精准的图像分…...
除了HDFS,DolphinScheduler资源中心还能怎么玩?聊聊S3与本地存储的配置差异
DolphinScheduler资源中心存储方案深度对比:从HDFS到S3的架构选型指南 在数据调度平台的实际部署中,存储后端的选型往往决定了系统整体的扩展性和运维成本。作为Apache DolphinScheduler的核心组件,资源中心支持多种存储类型配置,…...
如何通过Nginx反向代理部署WeTTY:生产环境完整配置指南
如何通过Nginx反向代理部署WeTTY:生产环境完整配置指南 【免费下载链接】wetty Terminal in browser over http/https. (Ajaxterm/Anyterm alternative, but much better) 项目地址: https://gitcode.com/gh_mirrors/we/wetty WeTTY(Web TTY&…...
别再只盯着模型了!Ansys SI/PI仿真中,用对IBIS的Pin Import才能抓准封装寄生效应
Ansys SI/PI仿真进阶:IBIS模型导入中Pin Import的封装寄生效应精准控制 在高速电路设计中,仿真结果的准确性往往决定了产品的成败。许多工程师花费大量时间优化PCB布局和模型参数,却忽略了IBIS模型导入这一关键环节对仿真精度的决定性影响。特…...
如何用Unity打造一款MMORPG:从零开始的全流程实战教程
如何用Unity打造一款MMORPG:从零开始的全流程实战教程 当《魔兽世界》《最终幻想14》等经典MMORPG持续创造商业奇迹时,许多开发者都怀揣着打造下一个爆款的梦想。Unity引擎凭借其跨平台能力和完善的工具链,已成为独立团队和中小厂商开发大型多…...
nli-distilroberta-base算法优化:利用LSTM思想增强序列上下文建模
nli-distilroberta-base算法优化:利用LSTM思想增强序列上下文建模 1. 效果展示背景 在自然语言推理任务中,nli-distilroberta-base作为轻量级Transformer模型表现出色,但在处理长文本序列时仍面临挑战。传统Transformer架构的自注意力机制虽…...
终极指南:如何快速导出并永久保存微信聊天记录
终极指南:如何快速导出并永久保存微信聊天记录 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 你是否曾担心更换手机后丢失宝贵的微信聊天记录?工…...
终极指南:如何安全自定义英雄联盟客户端视觉体验
终极指南:如何安全自定义英雄联盟客户端视觉体验 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank LeaguePrank是一款基于LCU API开发的英雄联盟视觉定制工具,专门帮助玩家在不修改游戏文件、不触碰内存的…...
