• 【C++】list容器


    目录

    list 基本概念

    list 构造函数

    list 赋值和交换

    list 大小操作

    list 插入和删除

    list 数据存取

    list 反转和排序

    list 排序案例


    list 基本概念

    功能:将数据进行链式存储

    -

    链表(list):是一种物理存储单位上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的

    -

    链表的组成:链表有一系列结点组成

    -

    结点的组成:两个部分,一部分是存储数据元素的数据域,另一部分是存储下一个地址的指针域

    -

    链表的优点:可以对任意位置进行快速插入和删除的操作

    -

    链表的缺点遍历速度慢(比数组),占用空间大(比数组)

    -

    STL中的链表是一个双向循环链表

    由于链表的存储方式并不是连续的内存空间,因此链表 list 中的迭代器只支持前移和后移,属于双向迭代器

    -

    list 优点

    • 采用动态存储分配,不会造成内存浪费和溢出(vector 容器的容量在创建空间很大时会不等于容器大小,这就是一定的空间浪费)
    • 链表执行插入和删除效率高

    -

    list 缺点

    • 链表灵活,但是空间(指针域)和时间(遍历)额外消耗大

    -

    list 有一个重要的性质,插入操作和删除操作都不会造成原有 list 迭代器的失效,这在 vector 是不成立的(重新分配新空间,将旧数据放到新空间,迭代器也就失效了)

    -

    在 STL 中 list 和 vector 是很常用的容器


    list 构造函数

    功能

    • 创建 list 容器

    函数原型

    1. // list采用模板类实现
    2. list lst;
    3. // 构造函数将 [beg, end) 区间中的元素拷贝给本身
    4. list(beg, end);
    5. // 构造函数将 n 个 elem 拷贝给本身
    6. list(n, elem);
    7. 拷贝构造函数
    8. list(const list& lst);

    测试代码:

    1. #include
    2. using namespace std;
    3. #include
    4. void PrintList(const list<int>& L) {
    5. for (list<int>::const_iterator Lit = L.begin(); Lit != L.end(); ++Lit) {
    6. cout << *Lit << " ";
    7. }
    8. cout << endl;
    9. }
    10. void test() {
    11. // 创建 list 容器
    12. list<int>L1;
    13. // 添加数据
    14. L1.push_back(10);
    15. L1.push_back(20);
    16. L1.push_back(30);
    17. L1.push_back(40);
    18. PrintList(L1); // 10 20 30 40
    19. // 区间的方式构造
    20. list<int>L2(L1.begin(), L1.end()); // 双向迭代器只能 ++、--
    21. PrintList(L2); // 10 20 30 40
    22. // n 个 elem
    23. list<int>L3(5, 10);
    24. PrintList(L3); // 10 10 10 10 10
    25. }
    26. int main() {
    27. test();
    28. system("pause");
    29. return 0;
    30. }

    运行结果:


    list 赋值和交换

    功能

    • 给 list 容器进行赋值,以及交换 list 容器

    函数原型

    1. // 将 [beg, end) 区间中的数据拷贝赋值给本身
    2. assign(beg, end);
    3. // 将 n 个 elem 拷贝赋值给本身
    4. assign(n, elem);
    5. // 重载 = 操作符
    6. list& operator=(const list& lst);
    7. // 将 lst 与本身的元素互换
    8. swap(lst);

    测试代码:

    1. #include
    2. using namespace std;
    3. #include
    4. void PrintList(const list<int>& L) {
    5. for (list<int>::const_iterator Lit = L.begin(); Lit != L.end(); ++Lit) {
    6. cout << *Lit << " ";
    7. }
    8. cout << endl;
    9. }
    10. void test() {
    11. list<int>L1;
    12. L1.push_back(10);
    13. L1.push_back(20);
    14. L1.push_back(30);
    15. L1.push_back(40);
    16. list<int>L2;
    17. // 将 [beg, end) 区间中的数据拷贝赋值给本身
    18. L2.assign(++L1.begin(), --L1.end()); // 双向迭代器,前置++--才有用
    19. PrintList(L2); // 20 30
    20. list<int>L3;
    21. // 重载 = 操作
    22. L3 = L1;
    23. PrintList(L3); // 10 20 30 40
    24. list<int>L4;
    25. // n 个 elem 赋值
    26. L4.assign(4, 10);
    27. PrintList(L4); // 10 10 10 10
    28. // swap 交换
    29. L4.swap(L3);
    30. PrintList(L3); // 10 10 10 10
    31. PrintList(L4); // 10 20 30 40
    32. }
    33. int main() {
    34. test();
    35. system("pause");
    36. return 0;
    37. }

    运行结果:


    list 大小操作

    功能:

    • 对 list 容器的大小进行操作

    函数原型:

    1. // 返回容器中元素的个数
    2. size();
    3. // 判断容器是否为空
    4. empty();
    5. // 重新指定容器的长度为 num,若容器变长,则以默认值填充新位置
    6. // 如果容器变短,则末尾超出容器长度的元素被删除
    7. resize(num);
    8. // 重新指定容器的长度为 num,若容器变长,则以 elem 填充新位置
    9. // 如果容器变短,则末尾超出容器长度的元素被删除
    10. resize(num, elem);

    测试代码:

    1. #include
    2. using namespace std;
    3. #include
    4. void PrintList(const list<int>& L) {
    5. for (list<int>::const_iterator Lit = L.begin(); Lit != L.end(); ++Lit) {
    6. cout << *Lit << " ";
    7. }
    8. cout << endl;
    9. }
    10. void test() {
    11. list<int>L1;
    12. // 判断是否为空,为空返回 true
    13. if (L1.empty()) {
    14. cout << "L1 为空" << endl;
    15. }
    16. else {
    17. cout << "L1 非空" << endl;
    18. }
    19. L1.push_back(10);
    20. L1.push_back(20);
    21. L1.push_back(30);
    22. L1.push_back(40);
    23. // 判断是否为空
    24. if (L1.empty()) {
    25. cout << "L1 为空" << endl;
    26. }
    27. else {
    28. cout << "L1 非空" << endl;
    29. cout << "L1 长度:" << L1.size() << endl;
    30. PrintList(L1); // 10 20 30 40
    31. // resize(num),超出的用 0 填充
    32. L1.resize(5); // 大小从 4 变成 5
    33. PrintList(L1); // 10 20 30 40 0
    34. // resize(num, elem),超出的用 elem 填充
    35. L1.resize(6, 10); // 大小从 5 变成 6
    36. PrintList(L1); // 10 20 30 40 0 10
    37. // resize(num),末尾多的删除
    38. L1.resize(4); // 大小从 6 变成 4
    39. PrintList(L1); // 10 20 30 40
    40. }
    41. }
    42. int main() {
    43. test();
    44. system("pause");
    45. return 0;
    46. }

    运行结果:


    list 插入和删除

    功能

    • 对 list 容器进行数据的插入和删除

    函数原型

    1. // 容器末尾添加一个元素
    2. push_back(elem);
    3. // 从容器末尾移除一个元素
    4. pop_back();
    5. // 从容器开头添加一个元素
    6. push_front(elem);
    7. // 从容器开头移除一个元素
    8. pop_front();
    9. // 在 pos(迭代器) 位置插 elem 元素的拷贝,返回新数据的位置
    10. insert(pos, elem);
    11. // 在 pos(迭代器) 位置插入 n 个 elem 数据,无返回值
    12. insert(pos, n, elem);
    13. // 在 pos(迭代器) 位置插入 [beg, end) (迭代器)区间数据,无返回值
    14. insert(pos, beg, end);
    15. // 移除容器所有数据
    16. clear();
    17. // 删除 [beg, end) (迭代器)区间的数据,返回下一个数据的位置
    18. erase(beg, end);
    19. // 删除 pos (迭代器)位置的数据,返回下一个数据的位置
    20. erase(pos);
    21. // 删除容器中所有与 elem 值匹配的元素
    22. remove(elem);

    测试代码:

    1. #include
    2. using namespace std;
    3. #include
    4. void PrintList(const list<int>& L) {
    5. for (list<int>::const_iterator Lit = L.begin(); Lit != L.end(); ++Lit) {
    6. cout << *Lit << " ";
    7. }
    8. cout << endl;
    9. }
    10. void test() {
    11. list<int>L1;
    12. // push_back(elem); 从尾部添加
    13. L1.push_back(10);
    14. L1.push_back(20);
    15. // push_front(elem); 从头部添加
    16. L1.push_front(-10);
    17. L1.push_front(-20);
    18. PrintList(L1); // -20 -10 10 20
    19. // pop_back(); 从尾部删除一个
    20. L1.pop_back();
    21. PrintList(L1); // -20 -10 10
    22. // pop_front(); 从头部删除一个
    23. L1.pop_front();
    24. PrintList(L1); // -10 10
    25. // insert(pos, elem); 在 pos 位置插入 elem 的拷贝,返回新数据位置
    26. L1.insert(L1.begin(), -20); // 开始位置插入 -20
    27. PrintList(L1); // -20 -10 10
    28. // insert(pos, n, elem); 在 pos 位置插入 n 个 elem 数据,无返回值
    29. L1.insert(L1.end(), 1, 20); // 最后一个位置插入 1 个 20
    30. PrintList(L1); // -20 -10 10 20
    31. list<int>L2;
    32. for (int i = 0; i < 5; i++) {
    33. L2.push_back(i + 1);
    34. }
    35. // insert(pos, beg, end); 在 pos 位置插入 [beg, end) 数据,无返回值
    36. L1.insert(L1.begin(), L2.begin(), L2.end());
    37. PrintList(L1); // 1 2 3 4 5 -20 -10 10 20
    38. // erase(beg, end); 删除 [beg, end) 区间数据,返回下一个数据的位置
    39. L1.erase(++L1.begin(), --L1.end()); // 双向迭代器,只能 ++-- ,前置才有效
    40. PrintList(L1); // 1 20
    41. // erase(pos); 删除 pos 位置数据,返回下一个数据的位置
    42. L1.erase(L1.begin());
    43. PrintList(L1); // 20
    44. L1.push_back(30);
    45. // clear(); 清空 list 容器数据
    46. L1.clear();
    47. if (!L1.size()) {
    48. cout << "L1 为空" << endl;
    49. }
    50. else {
    51. cout << "L1 非空" << endl;
    52. }
    53. PrintList(L1); // 空
    54. list<int>L3;
    55. L3.push_back(10);
    56. L3.push_back(20);
    57. L3.push_back(10);
    58. L3.push_back(20);
    59. L3.push_back(10);
    60. L3.push_back(20);
    61. // remove(num); 移除 list 容器中与 num 匹配的数据
    62. L3.remove(10);
    63. PrintList(L3); // 20 20 20
    64. }
    65. int main() {
    66. test();
    67. system("pause");
    68. return 0;
    69. }

    运行结果:


    list 数据存取

    功能

    • 对 list 容器中数据进行存取

    函数原型

    1. // 返回第一个元素
    2. front();
    3. // 返回最后一个元素
    4. back();

    不可以使用 [ ] 方式访问 list 容器

    不可以使用 at 方式访问 list 容器

    原因:本质是链表,每个数据不是用连续的线性空间存储的,迭代器也不支持随机访问

    测试代码:

    1. #include
    2. using namespace std;
    3. #include
    4. void PrintList(const list<int>& L) {
    5. for (list<int>::const_iterator Lit = L.begin(); Lit != L.end(); ++Lit) {
    6. cout << *Lit << " ";
    7. }
    8. cout << endl;
    9. }
    10. void test() {
    11. list<int>L1;
    12. L1.push_back(10);
    13. L1.push_back(20);
    14. L1.push_back(30);
    15. L1.push_back(40);
    16. cout << "第一个元素: " << L1.front() << endl;
    17. cout << "最后一个元素:" << L1.back() << endl;
    18. // 迭代器不支持随机访问
    19. list<int>::iterator it = L1.begin();
    20. //it = it + 1; // × 没有与操作符 + 匹配的运算符
    21. //it = it++; // √
    22. //it = it++; // 只能这样一步一步加
    23. //it = it--; // √,支持双向
    24. }
    25. int main() {
    26. test();
    27. system("pause");
    28. return 0;
    29. }

    运行结果:


    list 反转和排序

    功能

    • 将容器中的元素反转,以及将容器中的数据进行排序

    函数原型

    1. // 反转链表
    2. reverse();
    3. // 链表排序
    4. sort();

    测试代码:

    1. #include
    2. using namespace std;
    3. #include
    4. void PrintList(const list<int>& L) {
    5. for (list<int>::const_iterator Lit = L.begin(); Lit != L.end(); ++Lit) {
    6. cout << *Lit << " ";
    7. }
    8. cout << endl;
    9. }
    10. bool myCompare(int a, int b) {
    11. return (a > b);
    12. }
    13. void test() {
    14. list<int>L1;
    15. L1.push_back(9);
    16. L1.push_back(5);
    17. L1.push_back(8);
    18. L1.push_back(6);
    19. L1.push_back(7);
    20. cout << "反转前:";
    21. PrintList(L1); // 9 5 8 6 7
    22. cout << "反转后:";
    23. L1.reverse();
    24. PrintList(L1); // 7 6 8 5 9
    25. cout << "排序前:";
    26. PrintList(L1); // 7 6 8 5 9
    27. cout << "排序后:";
    28. L1.sort(); // 从小到大,想要降序再 reverse 一下
    29. PrintList(L1); // 5 6 7 8 9
    30. // sort() 还有一个重载的版本,可以降序
    31. cout << "降序: ";
    32. L1.sort(myCompare);
    33. PrintList(L1); // 9 8 7 6 5
    34. // 所有不支持随机访问迭代器的容器,不可以使用标准算法
    35. // sort(L1.begin(), L1.end()); // 错误
    36. }
    37. int main() {
    38. test();
    39. system("pause");
    40. return 0;
    41. }

    运行结果:


    list 排序案例

     案例:将 Person 自定义数据类型进行排序,Person 中属性有 name、age、high 

    -

    排序规则:按 age 进行升序,如果 age 相等就按 high 进行降序

    代码实例:

    1. #include
    2. using namespace std;
    3. #include
    4. #include
    5. class Person {
    6. friend void PrintList(list& P_List);
    7. friend bool comparePerson(Person& p1, Person& p2);
    8. public:
    9. Person(string name, int age, int high) :m_Name(name), m_Age(age), m_High(high) { }
    10. private:
    11. string m_Name;
    12. int m_Age;
    13. int m_High;
    14. };
    15. void PrintList(list& P_List) {
    16. for (list::iterator it = P_List.begin(); it != P_List.end(); ++it) {
    17. cout << "姓名:" << (*it).m_Name << " 年龄:" << it->m_Age << " 身高:" << (*it).m_High << endl;
    18. }
    19. }
    20. // 指定排序规则
    21. bool comparePerson(Person& p1, Person& p2) {
    22. if (p1.m_Age == p2.m_Age) {
    23. return p1.m_High > p2.m_High;
    24. }
    25. else {
    26. return p1.m_Age < p2.m_Age;
    27. }
    28. }
    29. void test() {
    30. listPerson_List;
    31. Person p1("李华", 18, 180);
    32. Person p2("张三", 19, 170);
    33. Person p3("王五", 20, 175);
    34. Person p4("赵六", 20, 170);
    35. Person p5("李四", 20, 180);
    36. Person_List.push_back(p1);
    37. Person_List.push_back(p2);
    38. Person_List.push_back(p3);
    39. Person_List.push_back(p4);
    40. Person_List.push_back(p5);
    41. cout << "排序前:" << endl;
    42. PrintList(Person_List);
    43. cout << "----------------------" << endl;
    44. cout << "排序后:" << endl;
    45. Person_List.sort(comparePerson);
    46. PrintList(Person_List);
    47. }
    48. int main() {
    49. test();
    50. system("pause");
    51. return 0;
    52. }

    运行结果:

  • 相关阅读:
    vs-debugger远程调试卡死解决
    MySQL库表占用空间排序
    基于事件驱动的任务分布式调度消费方案
    nginx php-fpm swoole
    java毕业生设计校园一卡通管理系统计算机源码+系统+mysql+调试部署+lw
    体育场馆LED显示屏的分类及应用
    金仓数据库KStudio使用手册(3. 数据库管理)
    第十四届蓝桥杯第一期模拟赛 python
    一、项目整合管理
    软文如何打动用户,媒介盒子教你几招
  • 原文地址:https://blog.csdn.net/xuan3215/article/details/126108747