【C++进阶】STL容器--list使用&&迭代器问题分析

本文详细介绍了C++中list容器的基本使用,包括构造函数、迭代器操作、capacity、元素访问和修改,以及迭代器失效问题和使用STL算法库函数时的注意事项。特别强调了list迭代器的特点和排序问题的处理方式。
摘要由CSDN通过智能技术生成

目录

前言

1. list的基本使用

1.1 list构造函数

1.2 list迭代器

 1.3 list capacity

1.4 list元素访问

 1.5 list 修改操作

insert

erase

 swap

 resize

 clear

2. list失效迭代器问题

3. list使用算法库函数问题

 总结


前言

        list(链表)在C++中非常重要的容器,它本质是一个带头双向循环链表。本文的主要内容是介绍list的基本使用以及对list迭代器问题。

在这里插入图片描述

1. list的基本使用

 学习一种新的容器,首先我们需要先了解它的接口;

 在C++的STL标准库中,list是一个带头双向循环链表;

 list和vector不同,它不支持[ ]下标随机访问;

list是一个双向链表,它的元素在内存中不是连续存储的,因此并不需要像vector一样预留容量或者调整容量

1.1 list构造函数

 C++98中默认有4中构造函数:

 有四种构造方法:

  • 默认无参构造
list<int> lt1;//无参构造
  • n个val构造
list<int> lt2(10,0); // 10个0初始化
  •  迭代器区间构造
vector<int> v{1,2,3,4,5};
list<int> lt3(v.begin(),v.end());
  •  拷贝构造
list<int> lt4(10,0);
list<int> lt5(lt4);

 除此之外还有比较常用的初始值设定项列表构造;

  •  initializer list构造(初始值设定项列表构造)
list<int> lt = {1, 2, 3, 4, 5};

1.2 list迭代器

 list迭代器本质并不是指针,为了方便理解,可暂时将迭代器理解成一个指针,该指针指向list中的某个节点;

 这4个迭代器接口大家都很熟悉,但需要注意的是list中它们的指向;

  •  list迭代器遍历
list<int> lt = { 1, 2, 3, 4, 5 };
list<int>::iterator it = lt.begin();
while (lt.end() != it)
{
	cout << *it << ' ';
	it++;
}
  •  范围for遍历
for (auto e : lt)
{
	cout << e << ' ';
}

范围for循环确实是本质上是迭代器遍历,在执行时会被替换成迭代器;

注意:

         在使用list迭代器时,我们往往使用的是it!=l.end(),而不是it<l.end(),因为list空间并不连续,每个节点的地址都不同(无法确认大小关系),在string和vector中,空间是连续的,可以使用;

 1.3 list capacity

 

 使用操作较为简单,使用list对象即可调用:

lt.empty();
lt.size();

1.4 list元素访问

 

 使用操作较为简单,使用list对象即可调用:

lt.front();
lt.back();

 1.5 list 修改操作

这里我们可以参考cplusplus上边的接口;

 这里我就介绍一些比较常用的,其他的接口使用可以去查阅;

头插、头删、尾插、尾删我就不再详细介绍;注意这些操作只能插入删除一个元素!

assign接口功能是新元素替换列表中的内容,它的功能我们完全可以使用list的构造函数替代,这里不再详细介绍;

insert

 

  •  使用单个值插入
list<int> mylist = {1, 2, 3, 4, 5};
auto it = mylist.begin();
it++; // 将迭代器it移动到第二个位置
mylist.insert(it, 10); // 在it位置插入值为10的元素
  • 使用相同值填充插入
list<int> mylist = {1, 2, 3, 4, 5};
auto it = mylist.begin();
it++; // 将迭代器it移动到第二个位置
mylist.insert(it, 3, 10); // 在it位置插入3个值为10的元素
  • 迭代器区间插入
list<int> mylist = {1, 2, 3, 4, 5};
auto it = mylist.begin();
it++; // 将迭代器it移动到第二个位置
vector<int> vec = {7, 8, 9};
mylist.insert(it, vec.begin(), vec.end()); // 在it位置插入vector中的元素
erase

 

  •  删除单个元素
list<int> mylist = {1, 2, 3, 4, 5};
auto it = mylist.begin();
it++; // 将迭代器it移动到第二个位置
mylist.erase(it); // 删除it位置的元素
  • 删除范围内的元素:
list<int> mylist = {1, 2, 3, 4, 5};
auto it1 = mylist.begin();
auto it2 = mylist.begin();
advance(it1, 1); // 将迭代器it1移动到第二个位置
advance(it2, 3); // 将迭代器it2移动到第四个位置
mylist.erase(it1, it2); // 删除从it1到it2范围内的元素

 注意list迭代器不支持使用+或-的操作来进行移动;所以这里使用advance函数来移动迭代器;

 swap

swap函数交换两个list的内容:

list<int> list1 = {1, 2, 3};
list<int> list2 = {4, 5, 6};
list1.swap(list2); // 交换list1和list2的内容
 resize

 resize函数调整list的大小:

list<int> mylist = {1, 2, 3, 4, 5};
mylist.resize(3); // 将mylist的大小调整为3,删除多余的元素
mylist.resize(5, 100); // 将mylist的大小调整为5,多出的元素用100填充

 list没有reserve接口

 clear

clear函数清空list的内容:

list<int> mylist = {1, 2, 3, 4, 5};
mylist.clear(); // 清空mylist的内容,mylist现在为空

2. list失效迭代器问题

         前面说过,此处大家可将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,list的底层结构为带头结点的双向循环链表,在list中进行插入时是不会导致list的迭代
器失效;

list迭代器失效只会在erase删除操作时发生

删除节点后,节点的数据就会被释放,再使用迭代器访问这个节点,此时节点已经失效;

前边我们也提到过,可以通过返回值的方法来避免迭代器的非法访问;

 节点被删除后,自动返回下一个位置的迭代器;

3. list使用算法库函数问题

 如果要对链表进行排序呢?

其实list自己封装的有sort接口,list链表的sort函数使用的是归并排序算法;那它为什么不用算法库里的sort;

原因很简单,其实就是迭代器不兼容;

 算法库里的sort它的参数是RandomAccessIterator,也就是随机访问迭代器;

这里就要补充一点知识,从不同容器的迭代器出发,容器不同迭代器实现也不同,那么迭代器的特性也不同;

根据迭代器的特性大致可以先分为三类: 

  • 单向迭代器(Forward Iterator) 
  • 双向迭代器(Bidirectional Iterator)
  • 随机访问迭代器(Random Access Iterator)

 单向迭代器: 迭代器仅++操作,单链表

 双向迭代器:迭代器支持++、--操作,双向链表

 随机访问迭代器:迭代器支持++/--/+/-操作,vector、string

 怎么分辨是否可以使用算法接口?

单向迭代支持++操作,满足所有迭代器的操作,三种类型的迭代器类型接口函数都可以使用;

 双向迭代器支持++/--操作,满足随机访问迭代器的操作,那它就可以使用参数类型为双向迭代器类型的接口函数,参数类型为随机访问迭代器类型的接口;

它就有向上兼容的特性;

 总结:

  • 单向迭代器可以使用三种迭代器类型的接口;
  • 双向迭代器可以使用:双向迭代器、随机迭代器类型的接口;
  • 随机迭代器仅可以使用随机迭代器类型的接口;

 虽然list自己实现的有sort接口,但还是不建议使用,它的效率非常的低;

它甚至还没有这样操作的速度快:

将list数据拷贝到vector中排序,然后将排序好的数据拷贝回list;


 总结

         本文主要介绍的是list的一些基本使用,以及list迭代器问题和list使用算法库函数的问题。list的接口函数不多,但是在使用算法库函数时需要注意迭代器的类型;以上便是本期的全部内容,希望对你有所帮助,感谢阅读!

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值