【C++要笑着学】list 常用接口介绍 | 支持任意位置O(1)插入删除的顺序容器 list(二)

简介: 一听 list ,我们就知道是个双向带头循环链表。list 在实际的运用中用的没有 vector 多,包括大家在刷题的时候 list 也出现的很少,因为 list 不支持随机访问,有很多数据堆在那里你可能还需要排序一下,list 要排序,就是一个大问题,所以用 vector 的情况较多。

Ⅲ. list 容量操作


0x00 size 返回有效节点个数

 size() 用于返回 list 中有效节点的个数。


💬 size:

void list_test6() {
  list<int> L;
  L.push_back(1);
  L.push_back(2);
  L.push_back(3);
  L.push_back(4);
  for (auto e : L) cout << e << " "; cout << endl;
  cout << "有效节点个数:";
  cout << L.size() << endl;
}

🚩 运行结果如下:

24643fc9d69ba9352b1d54d2ed83f21f_c601461abca44d3faa05e5ea2304cc7f.png


0x01 empty 检测容器是否为空

bc097b148333935456932cb3e5f0cf6b_da3498948c5d41e1b376b612a239e8a8.png

(之前讲 string 和 vector 的时候忘记提了)


empty 是用来检测容器是否为空的,如果为空则返回 true,否则返回 false。


这个我们在数据结构章节自己都实现过,返回一个布尔值:

9e12962d5a05a76d47d0480d7f8abbf7_899dc9866ce24ccba496d7cef1a89134.png

💬 empty:

void list_test7() {
  list<int> L;
  L.empty() == true ? cout << "为空" : cout << "不为空";
}

🚩 运行结果如下:

55dbd04f21b25a6fa0163b4507c60f56_8d06146f5f7d4d82b561f1e051abad4d.png


0x02 resize 调整容器大小

8765690119aeb92141b162be7830be0f_c20889ac6720448198887c72c95e4f12.png

list 中的 resize 和之前的 resize 的 "扩容" 有点不一样,它没有容量。


这里的 resize 是调整容器的大小,使其包含  个元素。


💬 用 resize 在 L 后面插入10 个 5:

void list_test8() {
  list<int> L;
  L.push_back(1);
  L.push_back(2);
  L.push_back(3);
  L.push_back(4);
  for (auto e : L) cout << e << " "; cout << endl;
  L.resize(10, 5);   // 插入10个5
  for (auto e : L) cout << e << " "; cout << endl;
}

🚩 运行结果如下:

a13023a74d7770fcbf424e0b0673fc78_f4811eb6c9dd487cbc73acc80d3dfec0.png


Ⅳ. 其他操作


0x00 reverse 逆置

edd552cb559e4c3adb0cb1abe5fc6ee6_acca3dcd65ac4c2bbc80ba90cbce89a7.png

用来逆置 list 中的元素。 (注意是 reverse,不是 reserve)


💬 将 L 的元素逆置:

void list_test9() {
  list<int> L;
  L.push_back(1);
  L.push_back(2);
  L.push_back(3);
  L.push_back(4);
  for (auto e : L) cout << e << " "; cout << endl;
  L.reverse();  // 将L的元素逆置
  for (auto e : L) cout << e << " "; cout << endl;
}

🚩 运行结果如下:

7785b2cad69ee6264c7e9f91747b9cc0_e5f9b5c52bbc47d3a68301e326086916.png

0x01 sort 排序

2ba079e3f090c177a22065289e45ef4d_f0c8827b9ab341d7ba6663dda076117d.png

💬 用 sort 对 L 中的元素进行排序:

void list_test9() {
  list<int> L;
  L.push_back(4);
  L.push_back(2);
  L.push_back(6);
  L.push_back(1);
  for (auto e : L) cout << e << " "; cout << endl;
  L.sort();   // 对L进行排序
  for (auto e : L) cout << e << " "; cout << endl;
}

🚩 运行结果如下:

e58cca408aba0a9edb144b6636aea7c4_b8776d0db76a4e84b8b237f247c9509c.png

(从小到大排序)


0x02 unique 去重

8002f90cea19bd683ea92cd2a55e9ee9_2045b922a79849108f0b1c225839a486.png

去重之前是有要求的,去重之前一定要先排序!如果不排序可能会去不干净。


💬 unique:

void list_test11() {
  list<int> L;
  L.push_back(2);
  L.push_back(1);
  L.push_back(2);
  L.push_back(1);
  for (auto e : L) cout << e << " "; cout << endl;
  L.sort(); // 去重前排个序
  cout << "去重后:";
  L.unique();
  for (auto e : L) cout << e << " "; cout << endl;
}

🚩 运行结果如下:

87c8ec9695545ae04441df05253a6bb8_18d60b761e0d4edab1e82047323148eb.png


💬 如果不排序,会导致去不干净情况发生:

void list_test11() {
  list<int> L;
  L.push_back(2);
  L.push_back(1);
  L.push_back(2);
  L.push_back(1);
  for (auto e : L) cout << e << " "; cout << endl;
  // L.sort(); // 去重前排个序
  cout << "去重后:";
  L.unique();
  for (auto e : L) cout << e << " "; cout << endl;
}

0daaf9246a854f4548a423399710e9b1_ef4a875ae2854122b617bb9c146844d5.png

0x03 remove 直接爽删

2418945df5f59f92bec0498fd7d7fee2_43b1974ea56e41eabc25f041c76c6c68.png

remove 可比 erase 爽太多,remove 只需要给一个元素的值,它就可以自己找自己删!


erase 还需要搞个搞个迭代器,然后还要 if 判断一下,但 remove 就不一样了。


💬 remove:

void list_test12() {
  list<int> L;
  L.push_back(10);
  L.push_back(20);
  L.push_back(30);
  L.push_back(40);
  for (auto e : L) cout << e << " "; cout << endl;
  // 如果删一个存在的元素
  L.remove(10);
  for (auto e : L) cout << e << " "; cout << endl;
  // 如果待删元素不存在
  L.remove(0);
  for (auto e : L) cout << e << " "; cout << endl;
}


🚩 运行结果如下:

8443cd1befee7bc59bf4df4866ed433f_0225b10e49604d93be9221ca45d64e35.png


自己去找自己去删,就是爽。而且就算要删元素不存在,也没有关系。


补充:remove() 函数用于从列表中删除所有出现的给定元素,而 remove_if() 函数用于从 list 中删除某些特定元素的集合。


0x04 splice 接合

d06322c25caca6f223b4692a7e3e741d_ce9cdae51cc34a5782e0f963a208ffd0.png

简单来说就是把一个链表转移到另一个链表里去。LRUCache,访问一个数据要调优先级的时候就用得到这个接口。我们这里先简单介绍一下。


💬 把 L2 的内容,接到 L1 的 begin() 前面:

void list_test13() {
  list<int> L1;
  L1.push_back(1);
  L1.push_back(2);
  L1.push_back(3);
  cout << "L1: ";
  for (auto e : L1) cout << e << " "; cout << endl;
  list<int> L2;
  L2.push_back(10);
  L2.push_back(20);
  L2.push_back(30);
  cout << "L2: ";
  for (auto e : L2) cout << e << " "; cout << endl;
  list<int>::iterator pos = L1.begin();
  L1.splice(pos, L2);  // 把L2的内容,接到L1的begin()前面
  cout << "接合后:";
  for (auto e : L1) cout << e << " "; cout << endl;
}


🚩 运行结果如下:


86c676af0b72db2a49fa63fd5d64fcf1_89fa4678c775440dabe1c0d9731ad4ab.png

相关文章
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
1002 1
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
363 9
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
378 5
【C++】实现日期类相关接口(三)
【C++】实现日期类相关接口
181 5
|
弹性计算 Kubernetes 网络协议
阿里云弹性网络接口技术的容器网络基础教程
阿里云弹性网络接口技术的容器网络基础教程
阿里云弹性网络接口技术的容器网络基础教程
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
365 2
|
存储 设计模式 C++
【C++】优先级队列(容器适配器)
本文介绍了C++ STL中的线性容器及其适配器,包括栈、队列和优先队列的设计与实现。详细解析了`deque`的特点和存储结构,以及如何利用`deque`实现栈、队列和优先队列。通过自定义命名空间和类模板,展示了如何模拟实现这些容器适配器,重点讲解了优先队列的内部机制,如堆的构建与维护方法。
290 0
|
设计模式 存储 C++
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现(二)
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现
221 0
|
存储 C++ 容器
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现(一)
【C++】C++ STL探索:容器适配器 Stack 与 Queue 的使用及模拟实现
246 0
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。