【C++】STL——list的使用

简介: 【C++】STL——list的使用

一. list的介绍


list即带头双向循环链表,支持在任意位置O(1)的插入和删除


0a2653c851af460fa595bd959398a8f1.png


二. list的构造函数



2d65d23f6d4748949b924e4057485923.png


方法一:无参构造


list<int> lt1; //构造int类型的空容器


方法二:n个val值构造


list<int> lt2(10,2)//构造10个值为2的int容器


方法三:拷贝构造


list<int> lt3(lt2)//lt2拷贝构造给lt3


方法四:迭代器区间构造


string s ("hello world")
list<int> lt4(s.begin(), s.end());


三. list的插入 & 删除


🎨push_front和pop_front


头插 头删


int main()
{
  list<int> lt;
  lt.push_front(0);
  lt.push_front(1);
  lt.push_front(2);
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl;
  lt.pop_front();
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl;
}


0a2653c851af460fa595bd959398a8f1.png


🎨push_back和pop_back


尾插尾删


int main()
{
  list<int> lt;
  lt.push_back(0);
  lt.push_back(1);
  lt.push_back(2);
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl;
  lt.pop_back();
  lt.pop_back();
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl;
}


0a2653c851af460fa595bd959398a8f1.png


🎨insert


list当中的insert函数支持三种插入方式:


指定位置插入一个数

指定位置插入n个val值的数

指定迭代器位置插入一段迭代器区间(左闭右开)

int main()
{
  list<int> lt;
  lt.push_back(1);
  lt.push_back(2);
  lt.push_back(3);
  list<int>::iterator pos = find(lt.begin(), lt.end(), 3);
  if(pos != lt.end())
  {
  lt.insert(pos, 20);
  }
  for (auto e : lt)
  {
  cout << endl;
  }
  cout << endl;// 1 2 20 3
  pos = find(lt.begin(), lt.end(), 3);
  if(pos != lt.end())
  {
  lt.insert(pos, 5, 30);//在三的位置插入5个30
  }
  for (auto e : lt)
  {
  cout << endl;
  }
  cout << endl;// 1 2 20 30 30 30 30 30 3
  vector<int> v(2, 7);
  list<int>::iterator pos = find(lt.begin(), lt.end(), 1);
  if(pos != lt.end())
  {
     lt.insert(pos, v.begin(), v.end()); //在1的位置插入2个7
  }
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //7 7 1 2 20 30 30 30 30 30 3
  return 0;
}


💢问:这里的pos会失效吗?

2d65d23f6d4748949b924e4057485923.png

不会,在pos位置前增加一个节点,并改变链接关系,但pos还是指向原本的位置,也不存在野指针


ps:由于find是stl各个容器都需要的,所以实现在了头文件algorithm.h中


🎨erase


4cebaac233b3433da32a72337a77fc60.png

int main()
{
  list<int> lt;
  lt.push_back(1);
  lt.push_back(2);
  lt.push_back(3);
  list<int>::iterator pos = find(lt.begin(), lt.end(), 2);
  if (pos != lt.end())
  {
  lt.erase(pos); //删除2
  }
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //1 3 4 5
  pos = find(lt.begin(), lt.end(), 4);
  if (pos != lt.end())
  {
  lt.erase(pos, lt.end()); //删除4及其之后的元素
  }
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //1 3
  return 0;
}


💢灵魂发问:此处的pos会失效吗?


打印崩溃了,显而易见,删除后,再访问就是野指针了


0a2653c851af460fa595bd959398a8f1.png


四. list的迭代器的使用


🌊正向迭代器


话不多说,上代码


#include <iostream>
#include <list>
using namespace std;
int main()
{
  list<int> lt(10, 2);
  //正向遍历
  list<int>::iterator it = lt.begin();
  while (it != lt.end())
  {
  cout << *it << " ";
  it++;
  }
  cout << endl;
  return 0;
}


🌊反向迭代器


#include <iostream>
#include <list>
using namespace std;
int main()
{
  list<int> lt(10, 5);
  //反向迭代器遍历容器
  list<int>::reverse_iterator rit = lt.rbegin();
  while (rit != lt.rend())
  {
  cout << *rit << " ";
  rit++;
  }
  cout << endl;
  return 0;
}


五. list元素的获取


🌍fornt & back


int main()
{
  list<int> lt;
  lt.push_back(1);
  lt.push_back(2);
  lt.push_back(3);
  cout << lt.front() << endl; 
  cout << lt.back() << endl; 
  return 0;
}


六. list的操作函数


⚡splice 转移


0a2653c851af460fa595bd959398a8f1.png

int main()
{
  list<int> lt1(4, 2);
  list<int> lt2(4, 6);
  lt1.splice(lt1.begin(), lt2); //将容器lt2拼接到容器lt1的开头
  for (auto e : lt1)
  {
  cout << e << " ";
  }
  cout << endl; //6 6 6 6 2 2 2 2 
  list<int> lt3(4, 2);
  list<int> lt4(4, 6);
  lt3.splice(lt3.begin(), lt4, lt4.begin()); //将容器lt4的第一个数据拼接到容器lt3的开头
  for (auto e : lt3)
  {
  cout << e << " ";
  }
  cout << endl; //6 2 2 2 2 
  list<int> lt5(4, 2);
  list<int> lt6(4, 6);
  lt5.splice(lt5.begin(), lt6, lt6.begin(), lt6.end()); //将容器lt6的指定迭代器区间内的数据拼接到容器lt5的开头
  for (auto e : lt5)
  {
  cout << e << " ";
  }
  cout << endl; //6 6 6 6 2 2 2 2
  return 0;
}


ps: 容器当中被拼接到另一个容器的数据在原容器当中就不存在了。(移植技术)


⚡remove


remove函数用于删除容器当中特定元素


int main()
{
  list<int> lt;
  lt.push_back(1);
  lt.push_back(1);
  lt.push_back(1);
  lt.push_back(3);
  lt.push_back(2);
  lt.push_back(2);
  lt.push_back(1);
  lt.push_back(3);
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //1 1 1 3 2 2 1 3
  lt.remove(1); //删除容器当中值为1的元素
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; 
  return 0;
}


⚡remove_if


remove_if函数用于删除容器当中满足条件的元素


bool single_digit(const int& val)
{
  return val < 10;
}
int main()
{
  list<int> lt;
  lt.push_back(10);
  lt.push_back(4);
  lt.push_back(7);
  lt.push_back(18);
  lt.push_back(2);
  lt.push_back(5);
  lt.push_back(9);
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //10 4 7 18 2 5 9
  lt.remove_if(single_digit); //删除容器当中值小于10的元素
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //10 18
  return 0;
}


⚡unique


unique函数用于删除容器当中连续的重复元素(前提是先排序)


int main()
{
  list<int> lt;
  lt.push_back(1);
  lt.push_back(4);
  lt.push_back(3);
  lt.push_back(3);
  lt.push_back(2);
  lt.push_back(2);
  lt.push_back(3);
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //1 4 3 3 2 2 3
  lt.sort(); //升序
  lt.unique(); 
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl;
  return 0;
}


⚡sort


算法库里面已经有一个sort 了,为什么list里也实现了一个sort?


list的空间不是连续的,算法库中的sort要求物理空间要是连续的,所以vector和string才用,快排实现的参数取中,在链表实现不了


链表的sort是归并排序实现的


int main()
{
  list<int> lt;
  lt.push_back(4);
  lt.push_back(7);
  lt.push_back(5);
  lt.push_back(9);
  lt.push_back(6);
  lt.push_back(0);
  lt.push_back(3);
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //4 7 5 9 6 0 3
  lt.sort(); //默认升序
  for (auto e : lt)
  {
  cout << e << " ";
  }
  cout << endl; //0 3 4 5 6 7 9
  return 0;
}
相关文章
|
6月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
345 2
|
存储 算法 C++
【c++丨STL】map/multimap的使用
本文详细介绍了STL关联式容器中的`map`和`multimap`的使用方法。`map`基于红黑树实现,内部元素按键自动升序排列,存储键值对,支持通过键访问或修改值;而`multimap`允许存在重复键。文章从构造函数、迭代器、容量接口、元素访问接口、增删操作到其他操作接口全面解析了`map`的功能,并通过实例演示了如何用`map`统计字符串数组中各元素的出现次数。最后对比了`map`与`set`的区别,强调了`map`在处理键值关系时的优势。
696 73
|
存储 缓存 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`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
算法 C++ 容器
模拟实现c++中的list模版
模拟实现c++中的list模版
|
存储 算法 C++
【c++丨STL】set/multiset的使用
本文深入解析了STL中的`set`和`multiset`容器,二者均为关联式容器,底层基于红黑树实现。`set`支持唯一性元素存储并自动排序,适用于高效查找场景;`multiset`允许重复元素。两者均具备O(logN)的插入、删除与查找复杂度。文章详细介绍了构造函数、迭代器、容量接口、增删操作(如`insert`、`erase`)、查找统计(如`find`、`count`)及`multiset`特有的区间操作(如`lower_bound`、`upper_bound`、`equal_range`)。最后预告了`map`容器的学习,其作为键值对存储的关联式容器,同样基于红黑树,具有高效操作特性。
565 3
|
C++ 容器
【c++丨STL】stack和queue的使用及模拟实现
本文介绍了STL中的两个重要容器适配器:栈(stack)和队列(queue)。容器适配器是在已有容器基础上添加新特性或功能的结构,如栈基于顺序表或链表限制操作实现。文章详细讲解了stack和queue的主要成员函数(empty、size、top/front/back、push/pop、swap),并提供了使用示例和模拟实现代码。通过这些内容,读者可以更好地理解这两种数据结构的工作原理及其实现方法。最后,作者鼓励读者点赞支持。 总结:本文深入浅出地讲解了STL中stack和queue的使用方法及其模拟实现,帮助读者掌握这两种容器适配器的特性和应用场景。
387 21
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
874 1
|
编译器 C语言 C++
【c++丨STL】list模拟实现(附源码)
本文介绍了如何模拟实现C++中的`list`容器。`list`底层采用双向带头循环链表结构,相较于`vector`和`string`更为复杂。文章首先回顾了`list`的基本结构和常用接口,然后详细讲解了节点、迭代器及容器的实现过程。 最终,通过这些步骤,我们成功模拟实现了`list`容器的功能。文章最后提供了完整的代码实现,并简要总结了实现过程中的关键点。 如果你对双向链表或`list`的底层实现感兴趣,建议先掌握相关基础知识后再阅读本文,以便更好地理解内容。
332 2
|
存储 算法 C++
深入浅出 C++ STL:解锁高效编程的秘密武器
C++ 标准模板库(STL)是现代 C++ 的核心部分之一,为开发者提供了丰富的预定义数据结构和算法,极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C++ 开发者来说至关重要。以下是对 STL 的详细介绍,涵盖其基础知识、发展历史、核心组件、重要性和学习方法。