当前位置: 首页 > news >正文

STL 容器:List

目录

  • 1 list 的概念
  • 2 list 的常用接口
    • 2.1 list 的构造函数
    • 2.2 list 的遍历
    • 2.3 list 的空间管理
      • 2.3.1 size()
      • 2.3.2 resize()
      • 2.3.3 empty()
    • 2.4 list 的增删改查
      • 2.4.1 front()
      • 2.4.2 back()
      • 2.4.4 push_front()
      • 2.4.5 pop_front()
      • 2.4.6 push_back()
      • 2.4.7 pop_back()
      • 2.4.8 insert()
      • 2.4.9 erase()
      • 2.4.10 swap()
      • 2.4.11 splice()
      • 2.4.12 remove()
      • 2.4.13 unique()
      • 2.4.14 merge()
      • 2.4.15 clear()
  • 3 list 的优缺点
  • 4 与 vector 的对比

1 list 的概念

list 是 STL 容器的一种,list 既可以用来保存内置类型数据(char,short,int等),又可以用来保存自定义类型数据(对象),它的底层数据结构是带头结点的双向循环链表

要想使用 list ,就需要包含头文件 list 并展开命名空间 std

#include <list>
using namespace std;

在这里插入图片描述

2 list 的常用接口

2.1 list 的构造函数

在构造 list 时,要遵循如下的语法:

list<类型名> 对象名;

list 的构造函数主要有以下几种:

在这里插入图片描述

(1)使用空间配置器进行构造,这个方式不太常用,因此在这里不做介绍

(2)使用 n 个 val 进行构造

用这种方式构造时,val 为用户给定的值,如果未给定,则它会使用缺省值(默认值),默认值为当前 list 存储的元素对应的类型的默认值,比如当前的 list 要存储 int 类型的值,那么它的默认值是 0,如果要存储 string,那么它的默认值是空字符串

list<int> list1(5, 1); //n = 5, val = 1

在这里插入图片描述

(3)使用其它容器的迭代器来确定区间,用区间内的元素来进行构造

用这种方式构造的时候,要保证 用于构造 list 的容器中所存储的数据的类型要和 list 中将要存储的数据的类型一致 ,也就是说,如果 list 中要存储 int 类型的数据,是不可以用 string 中存储的元素来进行构造的,因为 string 中存储的是字符

string s("hello world");
list<char> list1(s.begin(), s.end());

在这里插入图片描述

(4)使用一个已经存在的 list 来进行构造(拷贝构造)

用这种方式构造的时候,要保证两个 list 存储的数据的类型是一致的

list<int> list1(5, 1);
list<int> list2(list1);

在这里插入图片描述

(5)构造一个空的 list

如果在定义 list 时,对象名后不加括号,就会构造出一个空的 list

list<int> v3;

在这里插入图片描述

2.2 list 的遍历

由于 list 的底层是链表所以遍历不支持下标,只支持迭代器和范围 for

(1)使用迭代器遍历

在使用迭代器遍历时,会使用到以下几个接口:

接口名称作用返回值类型
begin()返回指向第一个元素的迭代器普通对象返回 iterator,const 对象返回 const_iterator
end()返回指向最后一个元素的下一个位置的迭代器普通对象返回 iterator,const 对象返回 const_iterator
rbegin()返回指向最后一个元素的迭代器普通对象返回 reverse_iterator,const 对象返回 const_reverse_iterator
rend()返回指向第一个元素的前一个位置的迭代器普通对象返回 reverse_iterator,const 对象返回 const_reverse_iterator

在这里插入图片描述

list 的迭代器属于双向迭代器,只能进行 ++,- - 操作, 支持双向遍历

正向遍历:

int main()
{list<int> list1 = { 1,2,3,4,5 };list<int>::iterator it = list1.begin();while (it != list1.end()){cout << *it << " ";it++;}return 0;
}

在这里插入图片描述

反向遍历:

int main()
{list<int> list1 = { 1,2,3,4,5 };list<int>::reverse_iterator rit = list1.rbegin();while (rit != list1.rend()){cout << *rit << " ";rit++;}return 0;
}

在这里插入图片描述

(2)范围 for 与 auto 遍历

int main()
{list<int> list1 = { 1,2,3,4,5 };for (auto e : list1){cout << e << " ";}return 0;
}

在 auto 后加上 & 就是 引用类型,由 auto& 修饰的变量 e 就是每一个元素的别名, 此时对 e 进行修改会影响结果,但不会影响 list 中元素的值

int main()
{list<int> list1 = { 1,2,3,4,5 };for (auto& e : list1){cout << e + 10 << " ";}return 0;
}

在这里插入图片描述

2.3 list 的空间管理

在对 list 进行空间管理时,经常会使用到以下几个接口:

接口名称作用返回值类型
size()返回 list 中存储的有效元素个数size_t (无符号整形)
resize()增加或缩减有效元素个数void
empty()判断 list 是否为空bool

在这里插入图片描述

2.3.1 size()

size 的主要作用是 返回当前 list 中有效元素的个数

int main()
{vector<int> v1 = { 1,2,3,4,5,6 };cout << v1.size() << endl;return 0;
}

在这里插入图片描述

2.3.2 resize()

在这里插入图片描述

resize 的主要作用是 对有效元素的个数进行缩减或增加

它的处理分两种情况:

(1)n > 当前有效元素个数

此时会在 list 中尾插若干个值为 val 的结点,直到有效元素个数为 n

其中 val 为用户给定的值,若没有给定则使用默认值

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.resize(10);return 0;
}

在这里插入图片描述

(2)n < 当前有效元素个数

此时会将超过 n 个有效元素的部分进行删除

int main()
{list<int> list1 = { 1,2,3,4,5,6 };cout << "size: " << list1.size() << endl;list1.resize(3);cout << "size: " << list1.size() << endl;return 0;
}

减少元素前:

在这里插入图片描述

减少元素后:

在这里插入图片描述

2.3.3 empty()

在这里插入图片描述

empty 的作用是 判断 list 是否为空,是空返回 true,不是空则返回 false

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2;if (list1.empty())cout << "list1 is empty" << endl;elsecout << "list1 is not empty" << endl;cout << endl;if (list2.empty())cout << "list2 is empty" << endl;elsecout << "list2 is not empty" << endl;return 0;
}

在这里插入图片描述

2.4 list 的增删改查

list 的增删改查接口主要有以下几种:

接口名称作用返回值类型
front()返回 list 的第一个元素引用
back()返回 list 的最后一个元素引用
push_front()在 list 中头插一个元素void
pop_front()在 list 中进行头删void
push_back()在 list 中尾插一个元素void
pop_back()在 list 中进行尾删void
insert()在 list 中插入元素Iterator/void
erase()在 list 中删除元素Iterator
swap()交换 list 中的所有元素void
splice()将一个 list 中的元素转移到另外一个中void
remove()清除 list 中符合要求的元素void
unique()清除 list 中重复的元素void
merge()合并两个有序的 listvoid
clear()清空 listvoid

在这里插入图片描述

2.4.1 front()

在这里插入图片描述
front 的作用是 访问 list 的第一个元素,返回该元素的引用对于 const 对象,返回的就是 const 引用,就意味着不能更改该对象的值

int main()
{list<int> list1 = { 1,2,3,4,5,6 };cout << list1.front() << endl;return 0;
}

在这里插入图片描述

2.4.2 back()

在这里插入图片描述
back 的作用是 访问 list 的最后一个元素,返回的也是该元素的引用, 对于 const 对象,返回的就是 const 引用,就意味着不能更改该对象的值

int main()
{vector<int> v1 = { 1,2,3,4,5,6 };cout << "v1 back:" << v1.back() << endl;return 0;
}

在这里插入图片描述

2.4.4 push_front()

push_front 的作用是 在 list 中进行头插并更改 size()

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.push_front(8);return 0;
}

在这里插入图片描述

2.4.5 pop_front()

pop_front() 的作用是 在 list 中进行头删并更新 size()

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.pop_front();return 0;
}

在这里插入图片描述

2.4.6 push_back()

push_back 的作用是 在 list 中尾插一个元素 val 并更新 size()

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.push_back(7);return 0;
}

在这里插入图片描述

2.4.7 pop_back()

在这里插入图片描述

pop_back 的作用是 删除 list 中的最后一个元素并更新 size()

int main()
{vector<int> v1 = { 1,2,3,4,5,6 };v1.pop_back();return 0;
}

在这里插入图片描述

2.4.8 insert()

在这里插入图片描述

insert 的作用是 在 list 中指定一个位置进行插入,插入的方式有三种:

(1)在指定位置插入一个值

此时在插入完成后,会返回 指向新元素的迭代器

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.insert(list1.begin(), 10);return 0;
}

在这里插入图片描述

(2)在指定的位置插入 n 个同样的值

在插入完成后,不进行任何返回

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.insert(list1.begin(), 5, 7);	return 0
}

在这里插入图片描述

(3)在指定位置插入一个区间内的值

这里的区间范围需要给出 起始迭代器终止迭代器 来确定,区间是左闭右开的,插入完成后,不会返回任何值

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2 = { 7,8,9 };list1.insert(list1.begin(), list2.begin(), list2.end());//[list2.begin(), list2.end())return 0;
}

在这里插入图片描述

2.4.9 erase()

在这里插入图片描述

erase 主要是 用来删除 list 中指定位置上的元素并更新size(),删除时,有两种方式:

(1)删除指定位置上的一个值

成功删除后,函数会 返回被删除元素的下一个位置的迭代器

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.erase(list1.begin());return 0;
}

在这里插入图片描述

(2)删除指定区间上的所有值

这里的区间范围需要给出 起始迭代器终止迭代器 来确定,区间是左闭右开的,删除完成后,会返回最后一个被删除元素的下一个位置的迭代器

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list1.erase(list1.begin(), list1.end());return 0;
}

在这里插入图片描述

需要注意的是,因为 list 的底层是双向循环带头结点的链表,删除元素就意味着释放元素所在的结点,如果删除后仍然使用被删除元素的迭代器,就会访问到已经被释放的空间,这是十分危险的行为,这也是一种迭代器失效

2.4.10 swap()

swap 的作用主要是 交换两个 list 中的值

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2 = { 7,8,9,10,11,12 };list1.swap(list2);return 0;
}

在这里插入图片描述

2.4.11 splice()

在这里插入图片描述
splice 主要是 用于将一个 list 中的元素转移至另外一个 list 的指定位置上

转换的方式有三种:

(1)将整个 list 进行转换

在这个转换的过程中,被用于转换的 list 会被清空

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2 = { 7,8,9,10,11,12 };list1.splice(list1.begin(), list2);return 0;
}

在这里插入图片描述

(2)指定 list 中的一个元素进行转换,该元素由迭代器 i 指向

在这个转换的过程中,被用于转换的元素会在原来的 list 中被删除

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2 = { 7,8,9,10,11,12 };list1.splice(list1.begin(), list2);return 0;
}

在这里插入图片描述

(3)指定 list 中一个区间内的值进行转换

区间需要由两个迭代器给出,分别表示 起始末尾区间是左闭右开的

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2 = { 7,8,9,10,11,12 };list1.splice(list1.begin(), list2, list2.begin(), list2.end());return 0;
}

在这里插入图片描述

2.4.12 remove()

remove 的作用是 移除 list 中所有值等于 val 的结点

int main()
{list<int> list1 = { 1,2,2,4,2,6 };list1.remove(2);return 0;
}

在这里插入图片描述

2.4.13 unique()

在这里插入图片描述
unique 的作用是 对 list 进行去重,将相等的多余的值进行移除前提是去重的 list 需要有序

int main()
{list<int> list1 = { 1,2,2,2,2,6 };list1.unique();return 0;
}

在这里插入图片描述

如果去重的 list 无序,那么就不能完全去重

int main()
{list<int> list1 = { 1,2,2,4,2,6 };list1.unique();return 0;
}

在这里插入图片描述

2.4.14 merge()

在这里插入图片描述
merge 的作用是将一个 list 合并到另外一个 list 中

合并时会将元素按序摆放,并且合并后,被合并的 list 会被清空

合并有两种方式:

(1)直接进行合并

直接进行合并时,默认是按照升序进行合并,此时要求两个 list 都为升序

int main()
{list<int> list1 = { 1,2,3,4,5,6 };list<int> list2 = { 2,3,4,5,6 };list1.merge(list2);return 0;
}

在这里插入图片描述

(2)合并时,按照给定的比较方式进行合并

比较方式为 x > y,那么就是 降序合并要求两个 list 都为降序
比较方式为 x < y,那么就是 升序合并要求两个 list 都为升序

bool comparison(int x, int y)
{return x > y;
}int main()
{list<int> list1 = { 6,5,4,3,2,1 };list<int> list2 = { 6,5,4,3,2 };list1.merge(list2, comparison);return 0;
}

在这里插入图片描述

2.4.15 clear()

clear 的作用是 清空 list 中的元素,将 size() 置为 0

这个操作相当于释放了 list 中的结点,只留下了虚拟头结点

int main()
{list<int> list1 = { 6,5,4,3,2,1 };list1.clear();return 0;
}

在这里插入图片描述

3 list 的优缺点

由于 list 的底层数据结构是带头结点的双向循环链表,所以它的优缺点就是该结构的优缺点:

优点:

  • 插入删除十分方便,时间复杂度低
  • 需要插入新的值时,直接创建新结点再链接即可,不需要进行扩容

缺点:

  • 不能随机访问,要查找值时,需要遍历一整个结构,效率低
  • 结点分散,容易造成内存碎片,空间利用率低

4 与 vector 的对比

对比vectorlist
底层数据结构动态顺序表带头结点的双向循环链表
访问效率支持使用下标随机访问,效率高不支持使用下标随机访问,效率低
插入删除效率尾插时可能原空间已满,需要开辟新空间,效率低,在头部和中间插入时,都需要将后方元素向后移动,时间复杂度是 O(N),尾删时,效率较高,不需要移动元素,在其他地方删除时,要将后方元素前移,时间复杂度是O(N)插入删除只需要改动结点的指针即可,效率高,并且不需要进行扩容,每次插入只需要开一个结点的空间即可
空间利用率空间连续,不会产生内存碎片,空间利用率高由于内部是一个个不连续的结点,所以容易产生内存碎片,空间利用率低
迭代器随机迭代器,支持进行 ++, - -,+,- 操作双向迭代器,只支持 ++, - - 操作
迭代器失效时机插入删除均会失效只有删除时会失效
使用场景插入删除频率低,访问频率高时使用插入删除频率高时使用
http://www.dtcms.com/a/523851.html

相关文章:

  • 做网站销售好累网上开店的货源渠道有哪些
  • 图像,视频Lora模型训练的Timestep Type时间步类型
  • 告别云端依赖!ComfyUI本地化视频生成实战教程+cpolar实战
  • Android16之如何获取APP、Bin进程的UID(二百六十三)
  • 在JavaScript / HTML中,无法通过开发者工具查看DOM元素中input里输入的密码
  • 像素塔防游戏:像素守卫者
  • 什么是栈?深入理解 JVM 中的栈结构
  • Go Web 编程快速入门 07.2 - 模板(2):解析与执行(含Demo)
  • 公司用wordpress建站用花钱大连网站设计开发
  • 建设网站需要下载神呢软件吗重庆企业网站推广公司
  • 常规面光源在工业视觉检测上的应用
  • 数据结构——直接插入排序
  • 如何开公司做网站素材免费网站
  • Spring Boot 配置优先级
  • 【架构】-- Nightingale:云原生监控告警平台的深度解析
  • 【Leetcode】
  • 以LIS为突破口的全栈信创实践——浙江省人民医院多院区多活架构建设样本
  • 使用 IntelliJ IDEA 连接 Docker
  • Maya Python入门: polySphere()球体的形状节点操作
  • 目前最好的引流方法上海专业seo
  • 第一篇使用HTML写一个随机点名网页
  • 沈阳网站设计制作电子商务网站上线活动策划
  • 使用 Undertow 替代 Tomcat
  • 搜维尔科技将携手Xsens|Haption|Tesollo|Manus亮相IROS 2025国际智能机器人与系统会议
  • 第四章-Tomcat线程模型与运行方式
  • 【PB案例学习笔记】-46在数据窗口中编辑数据
  • tomcat问题
  • 爱电影网站个人养老金制度将落地
  • 自己做游戏网站电子商务营销是什么意思
  • 基于深度学习的短视频内容理解与推荐系统_hadoop+flask+spider