【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语言开发实现的,关于大数据技术…...

Linux 下 Mysql 的使用(Ubuntu20.04)
文章目录 一、安装二、使用2.1 登录2.2 数据库操作2.2.1 创建数据库2.2.2 删除数据库2.2.3 创建数据表 参考文档 一、安装 Linux 下 Mysql 的安装非常简单,一个命令即可: sudo apt install mysql-server检查安装是否成功,输入: …...

牛客练习赛114
A.最后有0得数肯定是10得倍数,然后直接排序即可 #include<bits/stdc.h> using namespace std; const int N 1e610,mod1e97; int n; void solve(){cin>>n;vector<int> a(n);for(auto&i:a) cin>>i;sort(a.begin(),a.end(),greater<&g…...

Http与Https
1.简单介绍 HTTP:最广泛应用的网络通信协议,基于TCP,数据传输简单高效,数据是明文。 HTTPS:是HTTP的加强版,是HTTPSSL。在HTTP的基础上加了安全机制,一方面保证数据的安全传输,另一…...

前端通信(渲染、http、缓存、异步、跨域)自用笔记
SSR/CSR:HTML拼接?网页源码?SEO/交互性 SSR (server side render)服务端渲染,是指由服务侧(server side)完成页面的DOM结构拼接,然后发送到浏览器,为其绑定状…...

43.227.198.x怎么检查服务器里是否中毒情况?
要检查43.227.198.1服务器是否中毒,可以执行以下步骤: 运行杀毒软件:运行已安装的杀毒软件进行全盘扫描,查看是否有病毒或恶意软件。如果发现病毒或恶意软件,立即将其删除或隔离。 检查系统文件:检查服务器…...

Sentinel dashboard无法查询到应用的限流配置问题以及解决
一。问题引入 使用sentinle-dashboard控制台 项目整体升级后,发现控制台上无法看到流控规则了 之前的问题是无法注册上来 现在是注册上来了。结果看不到流控规则配置了。 关于注册不上来的问题,可以看另一篇文章 https://blog.csdn.net/a15835774652/…...

【Spring Boot】社交网站中验证用户登录的checkUser方法
public boolean checkUser(User user) {User userInDb userRepository.findByUsername(user.getUsername());if (userInDb ! null && userInDb.getPassword().equals(user.getPassword())) {return true;} else {return false;}} } 这段代码是UserService类中的checkU…...

edge浏览器进行qq截图过保爆决过程
edge浏览器进行qq截图过保解决过程 参考:电脑截屏曝光特别高怎么解决? - 知乎 问题展示 饱和度过高,刺眼 1. 在chrome地址栏输入chrome://flags/ 2. 在页面的搜索栏搜索force color profile 3. 在选项中选择所对应的颜色管理。(…...

【Linux】Linux在防火墙firewall中开放或删除某端口
在生产中往往是不能关闭防火墙firewall的(以下操作是在linux中执行的) #补充一下查看防火墙的命令 #查看防火墙状态 systemctl status firewalld #关闭防火墙 systemctl stop firewalld #重启防火墙 systemctl restart firewalld #启动防火墙 systemctl …...

C++构造函数初始化列表
构造函数的一项重要功能是对成员变量进行初始化,为了达到这个目的,可以在构造函数的函数体中对成员变量一一赋值,还可以采用初始化列表。 C构造函数的初始化列表使得代码更加简洁,请看下面的例子: #include <iostre…...