带你熟练使用list

简介: 带你熟练使用list

前言

官方查询文档


本文的目的主要是介绍list的常用接口,从构造函数,访问数据,修改数据等接口函数介绍.帮助大家初步掌握list的使用,后续会分享list的模拟实现,从底层理解list更加深刻的理解list.

一、构造函数:

121cdd0fd835485592a89171283113d8.png

函数模型 表头
explicit list(const allocator_type & alloc = allocator_type()); 无参构造
explicit list(size_type n, const value_type & val = value_type()) n个val初始化
list(InputIterator first, InputIterator last) 迭代器区间初始化
list(const list & x); 拷贝构造

学习了string和vector这里就不过多介绍了.

(1) 无参构造

测试代码:

void test1()
{
  //无参构造  explicit list(const allocator_type & alloc = allocator_type());
  list<int> L1;
  cout << "L1=";
  for (auto it : L1)
  {
    cout << it << " ";
  }
  cout << endl;
}

运行结果:

L1=

(2) 用n个val构造

  //使用n个val构造 explicit list(size_type n, const value_type & val = value_type())
  list<int> L2(5,2);
  cout << "L2=";
  for (auto it : L2)
  {
    cout << it << " ";
  }
  cout << endl;

运行结果:

L2=2 2 2 2 2

(3) 迭代器区间构造

  //迭代器区间构造
  //template <class InputIterator>
  //list(InputIterator first, InputIterator last)
  int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
  list<int> L3(arr, arr + 10);
  cout << "L3=";
  for (auto it : L3)
  {
    cout << it << " ";
  }
  cout << endl;

运行结果:

L3=1 2 3 4 5 6 7 8 9 10

(4) 拷贝构造

  //拷贝构造  list(const list & x);
  cout << "L4=";
  list<int> L4(L3);//上面的 L3=1 2 3 4 5 6 7 8 9 10
  for (auto it : L4)
  {
    cout << it << " ";
  }
  cout << endl;

运行结果:

L4=1 2 3 4 5 6 7 8 9 10

二、访问数据

(1) 迭代器

接口名 含义
begin() 返回第一个有效元素位置的迭代器
end() 返回最后一个有效元素位置的迭代器

(2) Element access:

接口名 含义
front() 返回list的第一个有效结点中存储的值的引用
back() 返回list的最后一个有效节点中存储的值的引用

测试代码:

void test2()
{
  //测试迭代器
  list<int> L1;
  L1.push_back(1);
  L1.push_back(4);
  L1.push_back(6);
  L1.push_back(8);
  L1.push_back(12);
  L1.push_back(20);
  list<int>::iterator it = L1.begin();
  while (it != L1.end())
  {
    cout << *it << " ";
    ++it;
  }
  cout << endl;
  //Element access:
  cout << "front()=" << L1.front() << endl; //返回list的第一个有效结点中存储的值的引用
  cout << "back()=" << L1.back() << endl;   //返回list的最后一个有效节点中存储的值的引用
}

运行结果:

1 4 6 8 12 20
front()=1
back()=20

三、修改(重点)

85d83815b2624759bc388a053f9fc9fd.png

接口名 解释
push_front 头插
pop_front 头删
push_back 尾插
pop_back 尾删
insert list中的 pos 位置中插入值为val的元素
erase 删除list 中的pos位置的元素
swap 交换两个list
clear 清除list中的有效数据

(1) 头插/删 && 尾插/删

void test3()
{
  list<int> L1;
  L1.push_back(1);
  L1.push_back(3);
  L1.push_back(4);
  L1.push_back(5);
  L1.push_back(7);
  L1.push_back(9);
  for (auto it : L1)
  {
    cout << it << " ";
  }
  cout << endl;
  //头插  
  L1.push_front(0);
  L1.push_front(-1);
  cout << "依次头插0 和-1后:  ";
  for (auto it : L1)
  {
    cout << it << " ";
  }
  cout << endl;
  //头删
  L1.pop_front();
  cout << "头删一次后:   ";
  for (auto it : L1)
  {
    cout << it << " ";
  }
  cout << endl;
  //尾删
  L1.pop_back();
  L1.pop_back();
  cout << "尾删两次后:   ";
  for (auto it : L1)
  {
    cout << it << " ";
  }
  cout << endl;
}

运行结果:

1 3 4 5 7 9
依次头插0 和-1后:       -1 0 1 3 4 5 7 9
头删一次后:             0 1 3 4 5 7 9
尾删两次后:             0 1 3 4 5

(2) insert && erase

🍔insert

a36c906467864d67b327b1fa46bab16c.png

接口名 解释
iterator insert (iterator position, const value_type& val); pos位置插入值val
void insert (iterator position, size_type n, const value_type& val); pos位置开始,插入nval
void insert (iterator position, InputIterator first, InputIterator last); pos位置插入,一个迭代器区间的值

由于list并不支持下标随机访问元素(" []"),所以,我们在使用迭代器的时候,避免使用

迭代器+ num

例如:L1.begin()+2

void test4()
{
  int arr[] = { 1,2,3,4,5,6,7,8 };
  list<int> L1(arr, arr + 8);
  for (auto it : L1)            //1 2 3 4 5 6 7 8
  {
    cout << it << " ";
  }
  cout << endl;
  // insert
  //iterator insert (iterator position, const value_type& val);\
  //list的迭代器不支持直接+=num
  //L1.insert(L1.begin()+2 ,66);  //报错
  auto it1 = L1.begin();
  ++it1;
  ++it1;
  L1.insert(it1, 66);
  for (auto it : L1)            //1 2 66 3 4 5 6 7 8
  {
    cout << it << " ";
  }
  cout << endl;
  //void insert(iterator position, size_type n, const value_type & val);
  L1.insert(L1.begin(), 3, 0);  //在第一个位置插入3个0
  for (auto it : L1)            //0 0 0 1 2 66 3 4 5 6 7 8
  {
    cout << it << " ";
  }
  cout << endl;
  //template <class InputIterator>
  //  void insert(iterator position, InputIterator first, InputIterator last);
  int arr2[] = { -1,-2,-3 };
  L1.insert(L1.begin(), arr2, arr2+3);  //在第一个位置插入一段迭代器区间的值
  for (auto it : L1)            //-1 -2 -3 0 0 0 1 2 66 3 4 5 6 7 8
  {
    cout << it << " ";
  }
  cout << endl;
}

e407bce9e0dc431a8721392bb00cbe6a.png

🍔erase

d72417e35a924eb59484135ce59bc68c.png

接口名 解释
iterator erase (iterator position); 删除该迭代器位置的值
iterator erase (iterator first, iterator last); 删除迭代器区间中的值

测试代码:

void test5()
{
  int arr[] = { 1,2,3,4,5,6,7,8 };
  list<int> L1(arr, arr + 8);
  for (auto it : L1)            //1 2 3 4 5 6 7 8
  {
    cout << it << " ";
  }
  cout << endl;
  //erase
  auto it1 = L1.end();    //指向最后一个有效元素的下一个位置
  --it1;          //指向最后一个有效元素的位置
  --it1;          //指向倒数第二个有效元素的位置
  L1.erase(it1);
  for (auto it : L1)            //1 2 3 4 5 6 8
  {
    cout << it << " ";
  }
  cout << endl;
  auto it2 = L1.begin();
  ++it2;
  auto it3 = L1.end();
  --it3;
  L1.erase(it2,it3);
  for (auto it : L1)            //1 8
  {
    cout << it << " ";
  }
  cout << endl;
}

2d1a2454afa34889a6388a667cc7f47d.png

(3) 迭代器失效问题

猜一猜这段代码的结果是什么?

void test6()
{
  int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  list<int> L1(arr, arr + 10);
  auto it = L1.begin();
  auto it2 = L1.end();
  --it2;
  while (it != it2)
  {
    // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,it就失效了
    L1.erase(it);
    ++it;
  }
  cout << endl;
}

8548651f65cc4305960a077909f1d095.gif

f6455c29d0124aad82727fbf7d3a788b.png

解释:

迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,插入并不会导致扩容而产生迭代器失效问题,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。


如下图:

48d32ede01934035aaf42633484050ad.png

那我该如何解决这个问题呢?

c99b0490bb8b43c1ba9c1404002639f7.png

void test6()
{
  int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  list<int> L1(arr, arr+10);
  auto it = L1.begin();
  auto it2 =L1.end();
  --it2;
  while (it != it2)
  {
    it=L1.erase(it);
  }
  for (auto it : L1)            
  {
    cout << it << " ";
  }
  cout << endl;
}

56dde36476c44e5a9109f314dbfeec95.png

下一篇,我们list模拟实现见吧!

8de360cea8204f359f7d899cf270bc87.png


目录
相关文章
|
域名解析 缓存 弹性计算
CDN 的操作与使用|学习笔记
快速学习 CDN 的操作与使用
CDN 的操作与使用|学习笔记
|
Go
Go语言中的默认参数和可选参数详解
【2月更文挑战第22天】
1448 2
|
测试技术 持续交付 开发工具
《Git 简易速速上手小册》第6章:Git 在持续集成/持续部署(CI/CD)中的应用(2024 最新版)
《Git 简易速速上手小册》第6章:Git 在持续集成/持续部署(CI/CD)中的应用(2024 最新版)
350 2
|
编解码 Java 编译器
【Protobuf】Protobuf中的Message语法规范
在Message中定义一个或者多个字段,FieldType是字段的数据类型,可以是基本类型(如int32、string、bool等)或其他定义的Message类型。fieldName是字段的名称,可以根据需求自定义。fieldNumber是字段的唯一标识号,用于在消息的二进制编码中标识字段。
970 0
|
开发工具 git
Git从远程仓库拉取指定的分支
Git从远程仓库拉取指定的分支
3431 0
|
SQL XML Java
Mybatis:SQL注入问题 like模糊查询 多表查询 动态SQL
Mybatis:SQL注入问题 like模糊查询 多表查询 动态SQL
2456 0
|
SQL 前端开发 安全
Gin-Vue-Admin 使用 gin+vue 进行极速开发的全栈开发基础平台【gva 第一节】
功能: 1.增加了 pgsql 数据库初始化,用户可选用 pgsql 进行开发。 2.增加了业务数据库功能,用户可通过 yaml 中配置自己的业务数据库,根据 name 获取业务库进行业务操作,实现框架和业务的数据库分离。 3.oss 集成了华为云 oss。 4.前端打包增加了提示内存不足时的一键 node 内存扩容 build 命令。 5.调整了获取用户信息的方法,增加了不鉴权模式下的用户信息获取方式。 6.配置页面调整。 7.取消了自动化代码中数据库类型和 size 的选择模块,防止自动化代码报错。
733 0
|
安全 网络协议 搜索推荐
信息收集简介
信息收集在渗透测试中至关重要,涉及侦察目标系统、网络、应用等,旨在确定攻击方向、提高测试效率和评估安全状况。信息收集分为主动(直接交互,如扫描)和被动(利用公开信息,如搜索引擎)。收集内容包括域名、服务器、网站、管理员信息等。常用方法包括:子域名枚举、IP扫描、Whois查询、DNS查询、网络拓扑分析、社会工程学、漏洞信息搜集、服务指纹识别、端口扫描和敏感文件探测。进行信息收集时,必须遵守法律,保持隐蔽,确保数据准确性。
524 4
|
Java API
[java进阶]——stream流你还不会用吗?超详细使用介绍
[java进阶]——stream流你还不会用吗?超详细使用介绍
347 0