• List基本使用(C++)


    目录

    1.list的介绍

    2.list的使用

    list的构造

    list的size() 和 max_size()

    list遍历操作

    list元素修改操作

    assign()函数

    push_front(),push_back 头插,尾插

    pop_front() pop_back 头删尾删

    insert()函数

    swap()函数

    resize()函数

    clear()函数

    list类数据操作

    splice()函数

    sort()函数

    unique()函数

    reverse()函数(逆置链表)


    1.list的介绍

    1.list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。

    2.list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。

    3.list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。

    4.与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移动元素的执行效率更好。

    5.与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第六个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

    2.list的使用

    list类为类模板,所以在使用时需要带上类型表示一个具体的类,例如数据类型为int类型的list使用时需要写为list

    list的构造

    1. #include
    2. using namespace std;
    3. #include
    4. #include
    5. int main() {
    6. //1.无参构造
    7. list<int> ls1;
    8. //list没有capacity
    9. cout << ls1.size() << endl;//0
    10. //2.指定个数类型值进行构造
    11. list<int> ls2(4,5);
    12. cout << ls2.size() <//4
    13. for(auto e : ls2){
    14. cout << e << " ";
    15. }
    16. cout << endl;//5 5 5 5
    17. //3.使用类对象迭代器区间进行构造
    18. list<int> ls3(ls2.begin(),ls2.end());
    19. cout << ls3.size() <//4
    20. for(auto e : ls3){
    21. cout << e << " ";
    22. }
    23. cout << endl;//5 5 5 5
    24. //也可以使用其然类对象迭代器区间进行构造
    25. vector<int> v(4,5);
    26. list<int> ls4(v.begin(),v.end());
    27. cout << ls4.size() <//4
    28. for(auto e : ls4){
    29. cout << e << " ";
    30. }
    31. cout << endl;//5 5 5 5
    32. //4.拷贝构造
    33. list<int> ls5(ls1);
    34. //list ls5 = ls1;
    35. cout << ls5.size() << endl;//0
    36. return 0;
    37. }

    list的size() 和 max_size()

    list遍历操作

    在list中,只有迭代器遍历方式

    list元素修改操作

    assign()函数

    使用assign()函数可以为调用对象链表重新分配内容,如果原始链表中有数据,那么将覆盖原始内容

    1. int main(){
    2. list<int> ls1(4,8);
    3. list<int> ls2 = {1,2,3,4,5};
    4. for(auto e : ls1)
    5. cout << e << " ";
    6. cout << endl;//8 8 8 8
    7. ls1.assign(ls2.begin(),ls2.end());
    8. for(auto e : ls1)
    9. cout << e << " ";
    10. cout << endl;//1 2 3 4 5
    11. return 0;
    12. }

    push_front(),push_back 头插,尾插

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. ls1.push_front(0);
    4. for(auto e : ls1)
    5. cout << e << " ";
    6. cout << endl;//0 1 2 3 4 5
    7. ls1.push_back(6);
    8. ls1.push_back(7);
    9. for(auto e : ls1)
    10. cout << e << " ";
    11. cout << endl;//0 1 2 3 4 5 6 7
    12. return 0;
    13. }

    pop_front() pop_back 头删尾删

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. ls1.pop_front();
    4. ls1.pop_front();
    5. for(auto e : ls1)
    6. cout << e << " ";
    7. cout << endl;//3 4 5
    8. ls1.pop_back();
    9. ls1.pop_back();
    10. for(auto e : ls1)
    11. cout << e << " ";
    12. cout << endl;//3
    13. return 0;
    14. }

    insert()函数

    对于insert()函数来说,基本不存在迭代器失效问题,因为list不存在扩容问题并且空间基本不是连续的,所以pos位置在插入数据后可能并没有改变

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. ls1.insert(ls1.end(), 6);
    4. ls1.insert(ls1.begin(), 2, 0);
    5. for(auto e : ls1)
    6. cout << e << " ";
    7. cout << endl;//0 0 1 2 3 4 5 6
    8. list<int> ls2 = {1,3,1,4};
    9. ls1.insert(ls1.begin(), ls2.begin(), ls2.end());
    10. for(auto e : ls1)
    11. cout << e << " ";
    12. cout << endl;//1 3 1 4 0 0 1 2 3 4 5 6
    13. return 0;
    14. }

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. list<int>::iterator it = find(ls1.begin(), ls1.end(), 2);
    4. it = ls1.erase(it);
    5. for (auto e : ls1)
    6. {
    7. cout << e << " ";
    8. }
    9. //1 3 4 5
    10. cout << endl << *it << endl;
    11. //3
    12. return 0;
    13. }

    swap()函数

    交换两个链表

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. cout << "ls1: ";
    4. for(auto e : ls1)
    5. cout << e << " ";
    6. cout << endl;
    7. list<int> ls2 = {5,4,3,2,1};
    8. cout << "ls2: ";
    9. for(auto e : ls2)
    10. cout << e << " ";
    11. cout << endl;
    12. swap(ls1, ls2);
    13. cout << "ls1: ";
    14. for(auto e : ls1)
    15. cout << e << " ";
    16. cout << endl;
    17. cout << "ls2: ";
    18. for(auto e : ls2)
    19. cout << e << " ";
    20. cout << endl;
    21. return 0;
    22. }

    resize()函数

    修改指定对象链表中的有效数据节点的个数

    当n小于当前链表的size,则实现删除效果,否则初始化为指定类型的数据(默认为对应类型的默认值)

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. cout << "ls1 size:" << ls1.size() << endl;
    4. //设定大小大于原来size,默认补充
    5. ls1.resize(10);
    6. cout << "ls1 size:" << ls1.size() << endl;
    7. for(auto e : ls1)
    8. cout << e << " ";
    9. cout << endl;
    10. //设定大小小于原来size,相当于删除
    11. ls1.resize(2);
    12. cout << "ls1 size:" << ls1.size() << endl;
    13. for(auto e : ls1)
    14. cout << e << " ";
    15. cout << endl;
    16. return 0;
    17. }
    18. 输出结果:
    19. ls1 size:5
    20. ls1 size:10
    21. 1 2 3 4 5 0 0 0 0 0
    22. ls1 size:2
    23. 1 2

    clear()函数

    使用clear()函数可以清空调用对象链表当前所有的有效数据节点(不会删除头节点)

    1. int main(){
    2. list<int> ls1 = {1,2,3,4,5};
    3. cout << "清空前:" << endl;
    4. for(auto e : ls1)
    5. cout << e << " ";
    6. cout << endl;
    7. ls1.clear();
    8. cout << "清空后:" << endl;
    9. for(auto e : ls1)
    10. cout << e << " ";
    11. cout << endl;
    12. return 0;
    13. }
    14. 清空前:
    15. 1 2 3 4 5
    16. 清空后:

    list类数据操作

    splice()函数

    使用splice()函数可以将指定对象中的内容拼接到调用对象的链表中的指定位置后(拼结后原链表不存在,只剩拼接后的新链表)

    1. int main(){
    2. list<int> ls1 = {1,3,1,4};
    3. list<int> ls2 = {5,2,0};
    4. ls1.splice(ls1.begin(), ls2);
    5. for(auto e : ls1)
    6. cout << e << " ";
    7. cout << endl;//5 2 0 1 3 1 4
    8. for(auto e : ls2)
    9. cout << e << " ";
    10. cout << endl;//ls2 内容为空
    11. return 0;
    12. }

    注意,splice()函数中的迭代器为双向迭代器(bidirectional iterator),传递的迭代器也必须为双向迭代器或者单向迭代器(forward iterator),不可以随机迭代器(random iterator)

    随机访问迭代器是特殊的双向迭代器,双向迭代器和随机访问迭代器是特殊的单向迭代器

    随机访问迭代器支持以下操作:

    双向迭代器支持以下操作:

    单向迭代器支持以下操作:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. list<int> ls{ 1,2,3,4,5 };
    8. vector<int> v1(3, 6);
    9. cout << "拼接前:" << endl;
    10. for (auto num : ls)
    11. {
    12. cout << num << " ";
    13. }
    14. cout << endl;
    15. for (auto num : v1)
    16. {
    17. cout << num << " ";
    18. }
    19. cout << endl;
    20. list<int>::iterator it = find(ls.begin(), ls.end(), 2);
    21. ls.splice(it, v1);
    22. cout << "拼接后:" << endl;
    23. for (auto num : ls)
    24. {
    25. cout << num << " ";
    26. }
    27. cout << endl;
    28. for (auto num : v1)
    29. {
    30. cout << num << " ";
    31. }
    32. cout << endl;
    33. return 0;
    34. }
    35. 报错信息:
    36. “std::list<int,std::allocator<int>>::splice”: 没有重载函数可以转换所有参数类型

    因为vector的迭代器为随机访问迭代器,所以当传入双向迭代器时会报错

    sort()函数

    使用sort()函数可以为调用对象的链表进行排序,底层是归并排序

    默认是升序排序,可以通过仿函数改变为降序(后续介绍仿函数)

    1. int main()
    2. {
    3. //升序
    4. list<int> ls = {9,0,3,2,21,43,11,0};
    5. for (auto num : ls)
    6. {
    7. cout << num << " ";
    8. }
    9. cout << endl;
    10. ls.sort();
    11. for (auto num : ls)
    12. {
    13. cout << num << " ";
    14. }
    15. cout << endl;
    16. //降序
    17. ls.sort(greater<int>());
    18. for (auto num : ls)
    19. {
    20. cout << num << " ";
    21. }
    22. return 0;
    23. }
    24. 9 0 3 2 21 43 11 0
    25. 0 0 2 3 9 11 21 43
    26. 43 21 11 9 3 2 0 0

    当list排序数据非常多的时候,可以考略将list数据拷贝到vector中排序,排序后再拷回list中。这段过程看似麻烦,但总体消耗时间比单独使用list中sort()函数小

    1. int main()
    2. {
    3. srand(time(NULL));
    4. const int N = 10000;//一万个数据
    5. list<int> ls;
    6. list<int> ls1;
    7. //向两个链表中插入数据
    8. for (int i = 0; i < N; ++i)
    9. {
    10. auto e = rand();
    11. ls.push_back(e);
    12. ls1.push_back(e);
    13. }
    14. //直接使用sort()排序
    15. size_t begin = clock();
    16. ls.sort();
    17. size_t end = clock();
    18. //拷贝到vector类中排序
    19. size_t begin1 = clock();
    20. vector<int> v(ls1.begin(), ls1.end());
    21. sort(v.begin(), v.end());
    22. ls1.assign(v.begin(), v.end());
    23. size_t end1 = clock();
    24. cout << "直接排序:" << end - begin << "ms" << endl;
    25. cout << "拷贝后排序再拷贝:" << end1 - begin1 << "ms" << endl;
    26. return 0;
    27. }
    28. 输出结果:
    29. 直接排序:2934ms
    30. 拷贝后排序再拷贝:586ms

    unique()函数

    unique()函数可以为链表去除重复数据的有效数据节点,但是使用unique()函数之前必须确保链表有序

    1. int main(){
    2. list<int> ls = {9,0,3,2,2,21,43,11,0};
    3. //进行升序
    4. ls.sort();
    5. for (auto e : ls)
    6. cout << e << " ";
    7. cout << endl;
    8. ls.unique();
    9. for (auto e : ls)
    10. cout << e << " ";
    11. cout << endl;
    12. return 0;
    13. }
    14. 输出结果;
    15. 0 0 2 2 3 9 11 21 43
    16. 0 2 3 9 11 21 43

    reverse()函数(逆置链表)

    1. int main(){
    2. list<int> ls = {1,2,3,4,5,6};
    3. ls.reverse();
    4. for (auto e : ls)
    5. cout << e << " ";
    6. cout << endl;//6 5 4 3 2 1
    7. return 0;
    8. }

     

  • 相关阅读:
    【C++ 学习 ㉖】- 布隆过滤器详解(哈希扩展)
    全新彩虹商城时光模板知识付费系统源码+内有5000多商品+易支付源码
    OS | 【三 内存管理】存储管理及大题解构
    基于上一篇博客,用阻塞队列实现异步下单
    ArcGIS_修改文本样式
    oracle数据库应用技术
    每日一题 712两个字符串的最小ASCLL删除和
    报错:为什么数组明明有内容但打印的length是0
    vue3(element-plus)+多语言切换实现
    Spring 框架知识点汇总 (持续更新)
  • 原文地址:https://blog.csdn.net/2202_75331338/article/details/139246999