C++ STL 中的 list 容器:用法与实现详解

链表与list

链表作为一种动态结构,能够根据需要的在运行时灵活的插入、删除数据元素,而且它对储存单元没有过高的要求,不一定要求核内存是连续的、整块单元。相对于数组、字符串,由于 链表存储不连续,因此不能实现对它的随机访问。在链表中查找、定位数据元素效率较低。无论如何,在很多问题中,链表还是能大展身手的,并高效的解决问题。

链表(Linked List)是一种线性数据结构,由一系列**节点(Node)**组成。每个节点包含两个部分:

数据域:存储实际的数据。

指针域:存储指向下一个节点(或上一个节点)的地址。

链表通过节点之间的指针连接起来,形成一个链式结构。

索引: 0       1       2       3       4
元素: A       B       C       D       E
地址: 0x1000  0x2000  0x3000  0x4000  0x5000
指针:----->----->----->-----> None

地址:每个节点在内存中的地址。
指针:指向下一节点的地址

链表有多种类型,常见的有
单向链表(Singly Linked List)
每个节点只有一个指针,指向下一个节点。
只能从头节点开始单向遍历。

示例:
头节点 -> 节点1 -> 节点2 -> 节点3 -> nullptr

双向链表(Doubly Linked List)
每个节点有两个指针,分别指向前一个节点和后一个节点。
可以从头节点或尾节点开始双向遍历。

示例:
nullptr <-> 节点1 <-> 节点2 <-> 节点3 <-> nullptr

循环链表(Circular Linked List)
单向链表或双向链表的变种,尾节点的指针指向头节点,形成一个环。

示例:
头节点 -> 节点1 -> 节点2 -> 节点3 -> 头节点

STL中的list容器

什么是 list?

  1. list 是一个双向链表容器,每个元素包含指向前后元素的指针。
  2. 与 vector 和 deque 不同,list 不支持随机访问,但插入和删除操作的时间复杂度为 O(1)。

list 的特点:

  1. 动态内存分配,不需要连续的内存空间。
  2. 支持双向遍历(从头到尾或从尾到头)。
  3. 高效的插入和删除操作,尤其是在中间位置。

构造及赋值

构造和赋值list含义
list< T > l默认构造空的l
list< T > l2(l1)用l1复制构造l2
list< T > l1(beg,end)由区间[beg,end)的元素构造l1
l2 = l1把l2赋值给l1

大小及存取

大小及存取含义
l.size()返回l中元素的个数
l.empty()判断l是否为空,l为空返回为true,用于此为目的时,比size更快
list< T >::iterator用于定义list< T >的迭代器类型
l.front()返回l的第一个元素,不检查链表是否为空
l.back()返回l的最后第一个元素,不检查链表是否为空
l.begin()返回l的第一个元素的位置
l.end()返回l的第一个最后元素的位置

插入与删除

插入含义
l.insert(pos,elem)在l的位置pos前将elem插入
l.insert(pos,n,elem)在l的位置pos前将n个elem插入
l.insert(begin,end)由区间[beg,end)的元素插入到l的pos位置前
l.push_back(elem)把元素elem追加到l的末端
l.push_front(elem)把元素elem追加到l的首端
删除含义
l.clear()删除l的所有元素
l.pop_front()删除l的第一个元素
l.pop_back()删除l的最后第一个元素
l.remove(val)删除l中所有值为val的元素
l.erase(pos)删除l中位置为pos的元素
l.erase(begin,end)删除l区间[beg,end)的元素
l.unique()删除l中重复的元素,保留第一次的出现

合并、逆转及排序

合并含义
l2.splice(pos,l1)将l1的所有元素转移到l2的位置pos前
l2.splice(pos,l1,pos1)将l1中位置为pos1元素转移到l2的位置pos前
l2.splice(begin,end)将l1中区间为[begin,end)的所有元素转移到l2的位置pos前
l1.merge(l2)把有序链表l2中的所有元素转移到l2的位置pos前
逆转和排序含义
l.reverse()将l中所有元素逆转
l.sort()将l中元素从小到大排序

值得注意的是,list不支持随机访问,因此不提供下标运算符和at()函数。list比较与vector的优势在与在任何位置插入和删除元素都很快,list的成员大多数执行的效率更高。
下面来举个例子帮助理解
将偶数和奇数装进两个不同的链表中,最后将两个链表排序后合并

#include <iostream>
#include <list>

int main() {
    // 初始链表
    std::list<int> originalList = {5, 2, 9, 1, 4, 6, 3, 8, 7};

    // 用于存储偶数和奇数的链表
    std::list<int> evenList; // 偶数链表
    std::list<int> oddList;  // 奇数链表

    // 将偶数和奇数分别装入两个链表
    for (int num : originalList) {
        if (num % 2 == 0) {
            evenList.push_back(num); // 偶数放入 evenList
        } else {
            oddList.push_back(num);  // 奇数放入 oddList
        }
    }

    // 对偶数链表和奇数链表进行排序
    evenList.sort(); // 偶数链表排序
    oddList.sort();  // 奇数链表排序

    // 输出排序后的偶数链表和奇数链表
    std::cout << "排序后的偶数链表: ";
    for (int val : evenList) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    std::cout << "排序后的奇数链表: ";
    for (int val : oddList) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    // 将偶数链表和奇数链表合并
    evenList.merge(oddList); // 合并后 evenList 包含所有元素,oddList 为空

    // 输出合并后的链表
    std::cout << "合并后的链表: ";
    for (int val : evenList) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    // 输出 oddList(应为空)
    std::cout << "合并后的 oddList: ";
    for (int val : oddList) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}
排序后的偶数链表:  2 4 6 8
排序后的奇数链表:: 1 3 5 7 9
合并后的链表: 1 2 3 4 5 6 7 8 9
合并后的 oddList: 

感谢您耐心阅读,希望这些关于list的知识能对您的编程学习有所助益!
若您有疑问之处请在评论区提出。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值