STL-list

打印 上一主题 下一主题

主题 2047|帖子 2047|积分 6141

一、 list的先容
std::list 是 C++ 标准模板库(STL)中的一种双向链表容器。每个元素包罗指向前后节点的指针,支持高效插入和删除利用,但随机访问性能较差。

 


 


 

 

1. list是可以在常数范围内在任意位置举行插入和删除的序列式容器,而且该容器可以前后双向迭代。
2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简朴高效。
4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置举行插入、移除元素的实行效率更好。
5. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,好比:要访问list的第6个元素,必须从已知的位置(好比头部大概尾部)迭代到该位置,在这段位置上迭代必要线性的时间开销;list还必要一些额外的空间,以保存每个节点的相关联信息(对于存储范例较小元素的大list来说这大概是一个重要的因素

 二、list的使用
  1. #include <iostream>
  2. #include <list>
  3. #include <algorithm>  // 用于 find 示例
  4. using namespace std;
  5. void printList(const string& hint, const list<int>& lst)
  6. {
  7.     cout << hint << ": ";
  8.     for (const auto& val : lst) cout << val << " ";
  9.     cout << "\n\n";
  10. }
  11. int main()
  12. {
  13.     // ================== 初始化 ==================
  14.     list<int> lst1;                  // 空列表
  15.     list<int> lst2(3, 100);          // 3个100
  16.     list<int> lst3 = { 7, 2, 5, 1 };   // 初始化列表
  17.     list<int> lst4(lst3);            // 拷贝构造
  18.     printList("lst2 (填充构造)", lst2);
  19.     printList("lst3 (初始化列表)", lst3);
  20.     printList("lst4 (拷贝构造)", lst4);
  21.     // ================== 增删操作 ==================
  22.     lst3.push_front(9);      // 头部插入
  23.     lst3.push_back(3);       // 尾部插入
  24.     printList("push_front(9) + push_back(3)", lst3); // 9 7 2 5 1 3
  25.     lst3.pop_front();        // 删除头部
  26.     lst3.pop_back();         // 删除尾部
  27.     printList("pop_front() + pop_back()", lst3);     // 7 2 5 1
  28.     auto it = lst3.begin();
  29.     advance(it, 2);                   // 移动到第3个元素(5)
  30.     lst3.insert(it, 99);               // 在5前面插入99
  31.     printList("insert(99) at pos3", lst3);  // 7 2 99 5 1
  32.     it = lst3.begin();
  33.     advance(it, 3);
  34.     lst3.erase(it);                   // 删除第4个元素(5)
  35.     printList("erase(pos4)", lst3);   // 7 2 99 1
  36.     lst3.remove(99);                  // 删除所有99
  37.     printList("remove(99)", lst3);    // 7 2 1
  38.     // ================== 容量操作 ==================
  39.     cout << "size: " << lst3.size() << endl;          // 3
  40.     cout << "empty: " << boolalpha << lst3.empty() << endl; // false
  41.     lst3.clear();
  42.     printList("after clear()", lst3);                // 空列表
  43.     cout << "empty after clear: " << lst3.empty() << endl << endl; // true
  44.     // ================== 元素访问 ==================
  45.     lst3 = { 10, 20, 30 };
  46.     cout << "front: " << lst3.front() << endl;  // 10
  47.     cout << "back: " << lst3.back() << endl;     // 30
  48.     cout << endl;
  49.     // ================== 特殊操作 ==================
  50.     list<int> lstA = { 5, 3, 1, 4, 2 };
  51.     lstA.sort();
  52.     printList("sorted lstA", lstA);  // 1 2 3 4 5
  53.     lstA.unique();                   // 无连续重复元素时无效
  54.     printList("unique (无变化)", lstA);
  55.     lstA.reverse();
  56.     printList("reversed lstA", lstA);  // 5 4 3 2 1
  57.     // splice示例
  58.     list<int> lstB = { 100, 200, 300 };
  59.     auto splice_pos = lstA.begin();
  60.     advance(splice_pos, 2);  // 插入到第3个位置前
  61.     lstA.splice(splice_pos, lstB);
  62.     printList("splice lstB into lstA", lstA);  // 5 4 100 200 300 3 2 1
  63.     printList("lstB after splice", lstB);      // 空列表
  64.     // merge示例(需要两个列表已排序)
  65.     list<int> lstC = { 2, 5, 8 };
  66.     list<int> lstD = { 1, 3, 6 };
  67.     lstC.merge(lstD);
  68.     printList("merged lstC", lstC);  // 1 2 3 5 6 8
  69.     printList("lstD after merge", lstD);  // 空列表
  70.     // ================== 遍历方式 ==================
  71.     cout << "迭代器遍历: ";
  72.     for (auto it = lstC.begin(); it != lstC.end(); ++it)
  73.     {
  74.         cout << *it << " ";
  75.     }
  76.     cout << "\n范围遍历: ";
  77.     for (const auto& val : lstC)
  78.     {
  79.         cout << val << " ";
  80.     }
  81.     cout << "\n\n";
  82.     // ================== 算法库结合示例 ==================
  83.     list<int> nums = { 5, 3, 9, 1, 7 };
  84.     auto find_it = find(nums.begin(), nums.end(), 9);
  85.     if (find_it != nums.end())
  86.     {
  87.         cout << "Found 9 at position: " << distance(nums.begin(), find_it) << endl;
  88.     }
  89.     return 0;
  90. }
复制代码
三、list的模拟实现
  1. #include <iostream>
  2. #include <cassert>
  3. #include <stdexcept>
  4. // 双向链表节点的模板定义
  5. template<typename T>
  6. struct ListNode
  7. {
  8.     T data;           // 节点存储的数据
  9.     ListNode* prev;   // 指向前一个节点的指针
  10.     ListNode* next;   // 指向后一个节点的指针
  11.     ListNode(const T& val) : data(val), prev(nullptr), next(nullptr) {}  // 构造函数初始化节点值
  12. };
  13. // 双向链表的模板类
  14. template<typename T>
  15. class List
  16. {
  17. private:
  18.     ListNode<T>* head;  // 指向链表头节点的指针
  19.     ListNode<T>* tail;  // 指向链表尾节点的指针
  20.     size_t size;        // 链表中元素的数量
  21. public:
  22.     // 默认构造函数:初始化一个空链表
  23.     List() : head(nullptr), tail(nullptr), size(0) {}
  24.    
  25.     // 析构函数:清空链表释放内存
  26.     ~List() { clear(); }
  27.     // 拷贝构造函数:创建一个新链表,内容与另一个链表相同
  28.     List(const List& other) : head(nullptr), tail(nullptr), size(0)
  29.     {
  30.         ListNode<T>* current = other.head;
  31.         while (current != nullptr)
  32.         {
  33.             push_back(current->data);  // 逐个复制元素
  34.             current = current->next;
  35.         }
  36.     }
  37.     // 移动构造函数:从另一个链表转移资源,避免深拷贝
  38.     List(List&& other) noexcept : head(other.head), tail(other.tail), size(other.size)
  39.     {
  40.         other.head = nullptr;  // 原链表置空
  41.         other.tail = nullptr;
  42.         other.size = 0;
  43.     }
  44.     // 拷贝赋值运算符:先清空当前链表,再复制另一个链表的内容
  45.     List& operator=(const List& other)
  46.     {
  47.         if (this != &other)
  48.         {
  49.             clear();  // 清空当前链表
  50.             ListNode<T>* current = other.head;
  51.             while (current != nullptr)
  52.             {
  53.                 push_back(current->data);  // 逐个复制元素
  54.                 current = current->next;
  55.             }
  56.         }
  57.         return *this;
  58.     }
  59.     // 移动赋值运算符:先清空当前链表,再转移另一个链表的资源
  60.     List& operator=(List&& other) noexcept
  61.     {
  62.         if (this != &other)
  63.         {
  64.             clear();  // 清空当前链表
  65.             head = other.head;
  66.             tail = other.tail;
  67.             size = other.size;
  68.             other.head = nullptr;  // 原链表置空
  69.             other.tail = nullptr;
  70.             other.size = 0;
  71.         }
  72.         return *this;
  73.     }
  74.     // 迭代器类:用于遍历链表
  75.     class iterator
  76.     {
  77.         ListNode<T>* current;  // 当前指向的节点
  78.     public:
  79.         iterator(ListNode<T>* node = nullptr) : current(node) {}  // 构造函数
  80.         
  81.         T& operator*() const { return current->data; }  // 解引用操作符
  82.         
  83.         // 前置自增运算符:指向下一个节点
  84.         iterator& operator++()
  85.         {
  86.             current = current->next;
  87.             return *this;
  88.         }
  89.         
  90.         // 后置自增运算符:返回当前迭代器,然后指向下一个节点
  91.         iterator operator++(int)
  92.         {
  93.             iterator tmp = *this;
  94.             current = current->next;
  95.             return tmp;
  96.         }
  97.         
  98.         // 相等比较运算符
  99.         bool operator==(const iterator& other) const { return current == other.current; }
  100.         
  101.         // 不等比较运算符
  102.         bool operator!=(const iterator& other) const { return current != other.current; }
  103.         
  104.         // 获取当前节点指针(供内部使用)
  105.         ListNode<T>* getCurrent() const { return current; }
  106.     };
  107.     iterator begin() const { return iterator(head); }  // 返回指向第一个元素的迭代器
  108.     iterator end() const { return iterator(nullptr); }  // 返回指向尾后的迭代器
  109.     // 判断链表是否为空
  110.     bool empty() const { return size == 0; }
  111.    
  112.     // 返回链表中元素的数量
  113.     size_t get_size() const { return size; }
  114.     // 返回第一个元素的引用
  115.     T& front()
  116.     {
  117.         if (empty()) throw std::out_of_range("List is empty");
  118.         return head->data;
  119.     }
  120.     // 返回最后一个元素的引用
  121.     T& back()
  122.     {
  123.         if (empty()) throw std::out_of_range("List is empty");
  124.         return tail->data;
  125.     }
  126.     // 在链表尾部添加元素
  127.     void push_back(const T& value)
  128.     {
  129.         ListNode<T>* newNode = new ListNode<T>(value);
  130.         if (!tail)  // 链表为空的情况
  131.         {
  132.             head = tail = newNode;
  133.         }
  134.         else  // 链表不为空的情况
  135.         {
  136.             tail->next = newNode;
  137.             newNode->prev = tail;
  138.             tail = newNode;
  139.         }
  140.         size++;
  141.     }
  142.     // 在链表头部添加元素
  143.     void push_front(const T& value)
  144.     {
  145.         ListNode<T>* newNode = new ListNode<T>(value);
  146.         if (!head)  // 链表为空的情况
  147.         {
  148.             head = tail = newNode;
  149.         }
  150.         else  // 链表不为空的情况
  151.         {
  152.             newNode->next = head;
  153.             head->prev = newNode;
  154.             head = newNode;
  155.         }
  156.         size++;
  157.     }
  158.     // 删除链表尾部的元素
  159.     void pop_back()
  160.     {
  161.         if (empty()) return;
  162.         ListNode<T>* temp = tail;
  163.         if (head == tail)  // 链表只有一个元素的情况
  164.         {
  165.             head = tail = nullptr;
  166.         }
  167.         else  // 链表有多个元素的情况
  168.         {
  169.             tail = tail->prev;
  170.             tail->next = nullptr;
  171.         }
  172.         delete temp;  // 释放内存
  173.         size--;
  174.     }
  175.     // 删除链表头部的元素
  176.     void pop_front()
  177.     {
  178.         if (empty()) return;
  179.         ListNode<T>* temp = head;
  180.         if (head == tail)  // 链表只有一个元素的情况
  181.         {
  182.             head = tail = nullptr;
  183.         }
  184.         else  // 链表有多个元素的情况
  185.         {
  186.             head = head->next;
  187.             head->prev = nullptr;
  188.         }
  189.         delete temp;  // 释放内存
  190.         size--;
  191.     }
  192.     // 清空链表:删除所有元素
  193.     void clear()
  194.     {
  195.         while (!empty())
  196.         {
  197.             pop_front();  // 逐个删除元素
  198.         }
  199.     }
  200.     // 在指定位置前插入元素,返回指向新插入元素的迭代器
  201.     iterator insert(iterator pos, const T& value)
  202.     {
  203.         if (pos == begin())  // 在头部插入
  204.         {
  205.             push_front(value);
  206.             return begin();
  207.         }
  208.         else if (pos == end())  // 在尾部插入
  209.         {
  210.             push_back(value);
  211.             return iterator(tail);
  212.         }
  213.         else  // 在中间插入
  214.         {
  215.             ListNode<T>* newNode = new ListNode<T>(value);
  216.             ListNode<T>* curr = pos.getCurrent();
  217.             newNode->prev = curr->prev;
  218.             newNode->next = curr;
  219.             curr->prev->next = newNode;
  220.             curr->prev = newNode;
  221.             size++;
  222.             return iterator(newNode);
  223.         }
  224.     }
  225.     // 删除指定位置的元素,返回指向下一个元素的迭代器
  226.     iterator erase(iterator pos)
  227.     {
  228.         if (pos == end()) return end();
  229.         ListNode<T>* curr = pos.getCurrent();
  230.         if (curr == head)  // 删除头部元素
  231.         {
  232.             pop_front();
  233.             return begin();
  234.         }
  235.         else if (curr == tail)  // 删除尾部元素
  236.         {
  237.             pop_back();
  238.             return end();
  239.         }
  240.         else  // 删除中间元素
  241.         {
  242.             ListNode<T>* prev = curr->prev;
  243.             ListNode<T>* next = curr->next;
  244.             prev->next = next;
  245.             next->prev = prev;
  246.             delete curr;  // 释放内存
  247.             size--;
  248.             return iterator(next);
  249.         }
  250.     }
  251. };
  252. // 测试用例:验证链表实现的正确性
  253. int main()
  254. {
  255.     // 测试默认构造函数
  256.     List<int> list1;
  257.     assert(list1.empty());
  258.     assert(list1.get_size() == 0);
  259.     // 测试push_back和front/back方法
  260.     list1.push_back(1);
  261.     assert(list1.get_size() == 1);
  262.     assert(list1.front() == 1);
  263.     assert(list1.back() == 1);
  264.     list1.push_back(2);
  265.     assert(list1.get_size() == 2);
  266.     assert(list1.front() == 1);
  267.     assert(list1.back() == 2);
  268.     // 测试push_front方法
  269.     List<int> list2;
  270.     list2.push_front(2);
  271.     assert(list2.get_size() == 1);
  272.     assert(list2.front() == 2);
  273.     list2.push_front(1);
  274.     assert(list2.get_size() == 2);
  275.     assert(list2.front() == 1);
  276.     assert(list2.back() == 2);
  277.     // 测试pop_back方法
  278.     list2.pop_back();
  279.     assert(list2.get_size() == 1);
  280.     assert(list2.back() == 1);
  281.     list2.pop_back();
  282.     assert(list2.empty());
  283.     // 测试pop_front方法
  284.     List<int> list3;
  285.     list3.push_back(1);
  286.     list3.push_back(2);
  287.     list3.pop_front();
  288.     assert(list3.get_size() == 1);
  289.     assert(list3.front() == 2);
  290.     list3.pop_front();
  291.     assert(list3.empty());
  292.     // 测试clear方法
  293.     List<int> list4;
  294.     list4.push_back(1);
  295.     list4.push_back(2);
  296.     list4.clear();
  297.     assert(list4.empty());
  298.     assert(list4.get_size() == 0);
  299.     try
  300.     {
  301.         list4.front();  // 尝试访问空链表的元素,应该抛出异常
  302.         assert(false);  // 如果没有抛出异常,断言失败
  303.     }
  304.     catch (const std::out_of_range&) {}  // 捕获预期的异常
  305.     // 测试拷贝构造函数
  306.     List<int> list5;
  307.     list5.push_back(1);
  308.     list5.push_back(2);
  309.     List<int> list6(list5);  // 拷贝构造
  310.     assert(list6.get_size() == 2);
  311.     assert(list6.front() == 1);
  312.     assert(list6.back() == 2);
  313.     list5.pop_front();  // 修改原链表
  314.     assert(list5.get_size() == 1);
  315.     assert(list6.get_size() == 2);  // 验证拷贝的链表不受影响
  316.     // 测试移动构造函数
  317.     List<int> list7(std::move(list5));  // 移动构造
  318.     assert(list7.get_size() == 1);
  319.     assert(list5.empty());  // 原链表应该被置空
  320.     // 测试拷贝赋值运算符
  321.     List<int> list8;
  322.     list8 = list6;  // 拷贝赋值
  323.     assert(list8.get_size() == 2);
  324.     list6.pop_back();  // 修改被拷贝的链表
  325.     assert(list8.get_size() == 2);  // 验证拷贝的链表不受影响
  326.     // 测试移动赋值运算符
  327.     List<int> list9;
  328.     list9 = std::move(list8);  // 移动赋值
  329.     assert(list9.get_size() == 2);
  330.     assert(list8.empty());  // 原链表应该被置空
  331.     // 测试插入和迭代器
  332.     List<int> list10;
  333.     list10.push_back(1);
  334.     list10.push_back(3);
  335.     auto it = list10.begin();
  336.     ++it;  // 指向元素3
  337.     list10.insert(it, 2);  // 在3之前插入2
  338.     assert(list10.get_size() == 3);
  339.     auto iter = list10.begin();
  340.     assert(*iter == 1);
  341.     ++iter;
  342.     assert(*iter == 2);
  343.     ++iter;
  344.     assert(*iter == 3);
  345.     ++iter;
  346.     assert(iter == list10.end());  // 验证迭代器到达尾部
  347.     // 测试删除
  348.     it = list10.begin();
  349.     ++it;  // 指向元素2
  350.     it = list10.erase(it);  // 删除元素2,it应该指向元素3
  351.     assert(*it == 3);
  352.     assert(list10.get_size() == 2);
  353.     assert(list10.front() == 1);
  354.     assert(list10.back() == 3);
  355.     std::cout << "All tests passed!" << std::endl;
  356.     return 0;
  357. }
复制代码
四、list的迭代器失效及反向迭代器
前面说过,此处各人可将迭代器暂时明确成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中举行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,而且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。

改正:
 

 反向迭代器的++就是正向迭代器的--,反向迭代器的--就是正向迭代器的++,因此反向迭
代器的实现可以借助正向迭代器,即:反向迭代器内部可以包罗一个正向迭代器,对正向迭代器的接口举行包装即可。
五、list和vector的区别


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

笑看天下无敌手

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表