STL-list
1.list
1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

2.list的使用
2.1 构造函数

void test1()
{//无参构造list<int> l1;//有参构造list<int> l2(10, 1);//10个1list<int> l3(10);//使用迭代器范围构造list<int> l4(l2.begin(), l2.end());//双向迭代器不支持加减法vector<int> v = { 1,2,3,4,5 };list<int> l5(v.begin() + 2, v.end());//拷贝构造list<int> l6(l5);//使用initializer_list初始化list<int> l7 = { 1,2,3,4,5,6,7,8 };
}
2.2operator=()

赋值运算符重载,进行深拷贝
//int类型
void PrintList(const list<int>& l)
{for (auto e : l){cout << e << ' ';}cout << endl;
}void test2()
{//operator=list<int> l1 = { 1,2,3 };list<int> l2;//深拷贝l2 = l1;PrintList(l1);PrintList(l2);
}
2.3begin() 和 end()

begin():返回第一个元素的双向迭代器,如果容器为空,则返回的迭代器值不能被解引用。
end():返回最后一个元素的下一位双向迭代器,如果容器为空,返回的迭代器与begin()返回的迭代器相同。
双向迭代器不支持加减法,支持 ++ 、 -- 、 * 、 == 、 != 、= 等操作。
void test3()
{//begin() and end()list<int> l = { 1,2,3,4,5,6,7,8 };list<int>::iterator it = l.begin();//返回双向迭代器while (it != l.end()){cout << *(it++) << ' ';}cout << endl;
}
2.4 rbegin() 和 rend()

rbegin():返回最后一个元素的反向双向迭代器
rend():返回第一个元素前一位的反向双向迭代器
使用++是向前迭代,--是向后迭代
void test4()
{list<int>l = { 1,2,3,4,5,6,7,8 };list<int>::reverse_iterator it = l.rbegin();while (it != l.rend()){cout << *(it++) << ' ';}cout << endl;
}
2.5 cbegin()、cend()、crbegin()、 crend()



无论调用对象是否const修饰,这四个函数返回const迭代器,不能通过迭代器修改指向内容,但迭代器本身可以改变。
2.6 empty()
判断容器是否为空,空返回true,非空返回false
void test5()
{list<int>l = { 1,2,3,4,5,6,7,8 };while (!l.empty()){cout << l.front() << ' ';l.pop_front();}
}
2.7 size()

用于返回有效元素个数

2.8 front()
返回容器第一个元素的引用,对空容器使用front是未定义行为

2.9 back()
返回容器最后一位元素的引用,对空容器使用back是未定义行为

2.10 assign()

将新内容替换原本的全部内容
void test8()
{//assignlist<int> l1 = { 1,2,3,4,5 };list<int> l2 = { 11,22 };vector<int> v = { 121,23,43,54,54,5,454 };//范围替换l1.assign(v.begin(), v.begin() + 3);l2.assign(l1.begin(), l1.end());PrintList(l1);PrintList(l2);//n个val替换l1.assign(10, 2);l2.assign(2, 0);PrintList(l1);PrintList(l2);
}
2.11 emplace_front

在开头构造并插入元素
在列表的开头插入一个新元素,就在它当前的第一个元素之前。这个新元素是使用args作为其构造的参数来就地构造的。
这有效地将容器大小增加了1。
该元素是通过调用allocator_traits::construct来就地构造的,并将参数转发。
存在一个类似的成员函数push_front,它复制或移动一个现有对象到容器中。

class A
{
public:A(int a, int b):_a(a), _b(b){cout << "构造" << endl;}A(const A& a){cout << "拷贝构造" << endl;}void Print(){cout << _a << ' ' << _b << endl;}
private:int _a;int _b;
};
void test10()
{list<A> l1;list<A> l2;l1.emplace_front(1,2);//直接构造并成为l1的元素//l2.push_front(1, 2);//errorl2.push_front({ 2,3 });//先隐式类型转换构造,再拷贝构造成l2的元素(*l1.begin()).Print();(*l2.begin()).Print();
}

2.12 push_front()

在容器第一个元素前插入一个元素, val的内容被拷贝(或移动)到插入的元素。
push_back()执行拷贝行为还是移动行为取决于传递给它的参数类型,传递左值触发拷贝构造函数执行拷贝行为,传递右值触发移动构造函数执行移动操作。
(在 C++ 中,左值(lvalue)和 右值(rvalue)是用来区分表达式的值在内存中的存在方式和生命周期的术语。)
移动构造函数是 C++11 引入的一种特殊构造函数,旨在高效地转移资源的所有权,而不是进行昂贵的复制。它通过移动语义来减少不必要的拷贝,提高程序性能。
移动构造函数通常在以下情况下被调用:
- 对象临时生命周期结束后:当你通过一个临时对象(右值)初始化另一个对象时,移动构造函数会被调用。
- 使用
std::move:当你显式调用std::move函数将一个对象转换为右值引用时,会触发移动构造函数。


2.13 pop_front()
用于删除第一个元素
2.14 emplace_back()

在末尾构造并插入元素
2.15 push_back()

在最后一个元素之后插入一个元素,val的内容被拷贝(或移动)到新元素。
2.16 pop_back()

删除最后一个元素
2.17 emplace()

在pos位置的元素之前构造并插入一个元素
2.18 insert()
在指定位置的元素之前插入新元素(一个或多个)
void test13()
{list<int> l1 = {1,2,3};vector<int> v = { 444,555,666,777 };auto it = l1.begin();//iterator insert (const_iterator position, const value_type& val);l1.insert(it, 0);PrintList(l1);//iterator insert (const_iterator position, size_type n, const value_type& val);it++;l1.insert(it, 3, 6);PrintList(l1);//template <class InputIterator>//iterator insert(const_iterator position, InputIterator first, InputIterator last);l1.insert(l1.begin(), v.begin() + 2, v.end());PrintList(l1);//iterator insert (const_iterator position, value_type&& val);//右值引用l1.insert(it, 9);PrintList(l1);//iterator insert(const_iterator position, initializer_list<value_type> il);l1.insert(it, { 11,12,13,14,15 });PrintList(l1);
}

2.19 erase()
从容器中删除一个或者范围内的元素
2.20 swap()

交换两个容器的内容
2.21 resize()

调整容器的有效元素的个数,使其包含n个元素
n小于当前个数,元素将减少到前n个,超出部分删除并销毁
n大于当前个数,元素将尾插至n个,如果指定了val,则新元素初始化为val的副本
class A
{
public:A(){cout << "无参构造" << endl;}A(int a, int b):_a(a), _b(b){cout << "有参构造" << endl;}A(const A& a){cout << "拷贝构造" << endl;}void Print(){cout << _a << ' ' << _b << endl;}
private:int _a;int _b;
};void test14()
{list<A> l1;l1.resize(2, {1,1});cout << "------" << endl;l1.resize(5);//3个无参构造
}

2.22 clear()
删除容器的所有内容
2.23 splice()
用于将元素从一个list转移到另一个list(转移:将元素从原来的list移除,原封不动转移到另一个list)


2.24 remove()
从容器中删除所有与val相同的元素

2.25 remove_if()

用于从容器中移除满足特定条件的元素
remove_if()传入一个谓语函数(返回bool值的函数)
2.26 unique()

删除相邻val值重复的元素
需要给整个容器去重:先排序,再unique
2.27 merge()

用于将两个已排序的列表合并成一个排序后的列表。需要注意的是,两个列表必须都是按顺序排列的。合并操作会通过移动节点来达成,而不需要额外分配内存。
两个列表的排序方式需要与合并成一个列表后的排序方式保持一致(即两个升序列表合并成一个升序列表,两个降序列表合并成一个降序列表)
2.28 sort()

sort() 函数会对列表中的元素进行升序排序。默认情况下,它使用元素的 < 运算符进行比较, 也可以提供一个自定义的比较函数。
list的sort()底层是基于归并排序实现的,归并排序在处理链表时的性能非常优越,因为它可以高效地操作节点而不需要额外的空间消耗。归并排序通过分割链表和合并已排序的部分,能够快速地处理链表的节点。
2.29 reverse()
用于反转list
2.30 关系运算符重载(非成员函数)

3.operator->()

为了可读性,强制剩下一个->
4. 部分模拟实现
#pragma once
#include<assert.h>namespace myList
{template<class T>struct ListNode{ListNode<T>* _next;ListNode<T>* _prev;T _data;ListNode(const T& data = T()):_next(nullptr),_prev(nullptr),_data(data){}};template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}// ++it;Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};//template<class T>//class ListConstIterator//{// typedef ListNode<T> Node;// typedef ListConstIterator<T> Self;// Node* _node;//public:// ListConstIterator(Node* node)// :_node(node)// {}// // ++it;// Self& operator++()// {// _node = _node->_next;// return *this;// }// Self& operator--()// {// _node = _node->_prev;// return *this;// }// Self operator++(int)// {// Self tmp(*this);// _node = _node->_next;// return tmp;// }// Self& operator--(int)// {// Self tmp(*this);// _node = _node->_prev;// return tmp;// }// //*it// const T& operator*()// {// return _node->_data;// }// const T* operator->()// {// return &_node->_data;// }// bool operator!=(const Self& it)// {// return _node != it._node;// }// bool operator==(const Self& it)// {// return _node == it._node;// }//};template<class T>class list{typedef ListNode<T> Node;public:// 不符合迭代器的行为,无法遍历//typedef Node* iterator;//typedef ListIterator<T> iterator;//typedef ListConstIterator<T> const_iterator;typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;iterator begin(){//iterator it(_head->_next);//return it;return iterator(_head->_next);}const_iterator begin() const{return const_iterator(_head->_next);}iterator end(){return iterator(_head);}const_iterator end() const{return const_iterator(_head);}void empty_init(){_head = new Node();_head->_next = _head;_head->_prev = _head;}list(){empty_init();}list(initializer_list<T> il){empty_init();for (const auto& e : il){push_back(e);}}// lt2(lt1)list(const list<T>& lt){empty_init();for (const auto& e : lt){push_back(e);}}// lt1 = lt3list<T>& operator=(list<T> lt){swap(_head, lt._head);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){auto it = begin();while (it != end()){it = erase(it);}}void push_back(const T& x){/*Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;*/insert(end(), x);}void pop_back(){erase(--end());}void push_front(const T& x){insert(begin(), x);}void pop_front(){erase(begin());}// 没有iterator失效iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* newnode = new Node(x);Node* prev = cur->_prev;// prev newnode curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}// erase 后 pos失效了,pos指向节点被释放了iterator erase(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;return iterator(next);}private:Node* _head;};
}
相关文章:
STL-list
1.list 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。 3. l…...
2024 7.29~8.4 周报
一、上周工作 2024 7.22~7.28周报-CSDN博客 二、本周计划 修改论文 三、完成情况 3.1 论文修改 3.1.1 摘要 问题:所写问题是一般性的深度网络问题(过拟合),并没有针对FWI的问题(边缘不清晰、深层不清晰、速度慢…...
随身助手271个可用api接口网站php源码(随身助手API)
源码简介: 随身助手API,本次更新了271个可用接口,现在开源给大家使用,无后门无加密,放心使用。 {“标题”:”看图猜成语接口”,”小标题”:”随身助手API”,”地址”:”tianyi/LookIdiom.php”,”状态”:”正常”} {…...
珠江电缆,顺应全球变化,实现高质量出海
在全球经济快速变化的今天,越来越多的企业将目光投向了国际市场。特别是对于线缆行业来说,顺应全球变化、应对机遇与挑战,实现高质量出海已成为长期发展的战略目标之一。珠江电缆作为一家集研发、制造和销售为一体的大型专业电线电缆企业&…...
redis面试(四)持久化
什么是持久化? 由于redis是基于内存操作的轻量型数据库,所以如果发生宕机重启这种事情,存储的数据就会直接丢失,如果在里面存储了没有备份的数据,那么确实会对我们的业务造成一定影响。 所以我们要通过持久化的手段&a…...
构建数据桥梁:Pandas如何简化API到DataFrame的转换
在数据科学的广阔天地中,API如同一把钥匙,为我们打开了通往丰富数据资源的大门。无论是追踪最新的股市动态,还是分析社交媒体趋势,API都能提供我们需要的实时数据。今天,我们将一起探索如何利用Python的pandas库&#…...
echarts制作grafana 面板之折线图
最近有需求需要制作grafana 来实现自己的需求,于是开始研究 实现效果如下 实现代码 import * as echarts from echarts;var chartDom document.getElementById(main); var myChart echarts.init(chartDom, dark); var option;function getLast30Days() {let da…...
技术男的审美反击:UI配置化新纪元
之前常常被甲方的领导说,我们全是一群钢铁直男,一点不懂审美,其实我们心里边想的 “您说得对啊!!!!” 这个可能和理工科有关系吧,理工男好像都差不多,所以这次我们就把很…...
73.结构体指针参数传递
目录 一.结构体指针参数传递 二.视频教程 一.结构体指针参数传递 结构体指针也可以作为参数传递,相对于结构体变量参数传递,结构体指针变量作为函数参数传递速度更快,效率更高。 举例: #include <stdio.h> #include <…...
面向对象编程与Scala:掌握核心概念与应用
面向对象编程与Scala:掌握核心概念与应用 1. 引言 Scala 是一种融合了面向对象编程(OOP)和函数式编程(FP)特性的编程语言。它为开发者提供了强大的工具来创建高效且灵活的软件。面向对象编程是一种编程范式ÿ…...
《Advanced RAG》-07-探索 RAG 中表格数据的处理方案
摘要 本文详细讨论了实现 Retrieval-Augmented Generation(RAG)时对表格进行处理的挑战,特别是在非结构化文档中自动准确地提取和理解表格信息。 首先介绍了RAG中管理表格的关键技术,包括表格解析和索引结构设计。 接着࿰…...
Dubbo源码深度解析(二)
接着《Dubbo源码深度解析(一)》继续讲,上篇博客主要讲Dubbo提供的三个注解的作用,即:EnableDubbo、DubboComponentScan、EnableDubboConfig。其中后两个注解是在EnableDubbo上的,因此在启动类上加上EnableDubbo注解,等…...
RocketMQ 的高可用性:主从复制与多副本保证
RocketMQ 是一款开源的分布式消息队列系统,广泛应用于大规模分布式应用中。高可用性是 RocketMQ 的核心特性之一,通过主从复制和多副本保证,RocketMQ 能够确保消息的可靠传递和系统的高可用性。 什么是高可用性? 高可用性&#…...
Linux系统驱动(四)自动创建设备节点
自动创建设备节点 (一)创建设备节点的机制 1. mknod 将驱动编译到内核中,在内核启动时驱动自动被安装执行 2.devfs(2.4内核) 3. udev(2.6内核至今) 注:hotplug — 热插拔 &…...
Webpack、Vite区别知多少?
前端的项目打包,我们常用的构建工具有Webpack和Vite,那么Webpack和Vite是两种不同的前端构建工具,那么你们又是否了解它们的区别呢?我们在做项目时要如何选择呢? 一、工具定义 1、Webpack:是一个强大的静态模块打包工…...
《剑指编程之巅:大学新生,以诗心驭代码》
《剑指编程之巅:大学新生,以诗心驭代码》 月华如水,洒落书窗,吾辈学子,正逢盛世,编程之术,已成必修之课。然则,编程语言如繁星点点,学习资源浩瀚如海,新生初…...
【八股文】网络基础
1.简述一下TCP和UDP的区别? 特性TCP(Transmission Control Protocol)UDP(User Datagram Protocol)连接类型面向连接,需要建立三次握手连接无连接,发送数据无需建立连接数据传输提供可靠的数据传…...
Nginx进阶-常见配置(一)
一、nginx Proxy 反向代理 1、代理原理 反向代理产生的背景: 在计算机世界里,由于单个服务器的处理客户端(用户)请求能力有一个极限,当用户的接入请求蜂拥而入时,会造成服务器忙不过来的局面,…...
九/十:C语言-扫雷游戏实现与函数递归
九:数组和函数实践:扫雷游戏 1.扫雷游戏的分析和设计 (1)扫雷游戏功能说明: 使用控制台实现经典的扫雷游戏游戏可以通过菜单实现暂停或者退出游戏扫雷的游戏界面是9*9的格子默认随机布置10个雷可以排查雷࿱…...
【Android Studio】gradle文件、配置、版本下载、国内源(gradle版本以及gradle-plugin版本)
文章目录 AS查看gradle-plugin版本及gradle版本(图形)查看gradle-plugin版本及gradle版本(配置文件)配置文件分析解决gradle下载失败、版本错乱等问题。 Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的自动化构建工具&…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
算法打卡第18天
从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7…...


