带你熟练使用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


目录
相关文章
|
10天前
|
Java 机器人 程序员
从入门到精通:五种 List 遍历方法对比与实战指南
小米是一位热爱分享技术的程序员,本文详细介绍了 Java 中遍历 List 的五种方式:经典 for 循环、增强 for 循环、Iterator 和 ListIterator、Stream API 以及 forEach 方法。每种方式都有其适用场景和优缺点,例如 for 循环适合频繁访问索引,增强 for 循环和 forEach 方法代码简洁,Stream API 适合大数据量操作,ListIterator 支持双向遍历。文章通过生动的小故事和代码示例,帮助读者更好地理解和选择合适的遍历方式。
27 2
|
2月前
|
存储 C++ 容器
C++入门9——list的使用
C++入门9——list的使用
22 0
|
6月前
|
C++ 容器
9.STL中list的常见操作(图文并茂)
9.STL中list的常见操作(图文并茂)
|
6月前
|
机器学习/深度学习 安全 Shell
必知的技术知识:find用法详解
必知的技术知识:find用法详解
|
6月前
|
存储 Java 开发者
为什么Java开发者都爱List?看完这篇你就懂了!
【6月更文挑战第17天】Java开发者青睐List,因其作为有序、动态和可索引的元素集合,便于排序查找。List允许运行时动态添加、删除元素,适合处理需保持顺序的场景。例如,存储排序后的订单列表,List能轻松实现添加、排序和索引访问修改,体现了其灵活性和实用性。
40 0
|
7月前
|
算法 C++ 容器
【C++进阶(四)】STL大法--list深度剖析&list迭代器问题探讨
【C++进阶(四)】STL大法--list深度剖析&list迭代器问题探讨
|
7月前
|
C++
c++的学习之路:15、list(2)
c++的学习之路:15、list(2)
41 0
|
7月前
|
C++
c++的学习之路:16、list(3)
c++的学习之路:16、list(3)
40 0
|
7月前
|
存储 C++ 容器
c++的学习之路:14、list(1)
c++的学习之路:14、list(1)
45 0
|
7月前
|
存储 Java 程序员
List:程序员的得力助手
List:程序员的得力助手
52 0