手撕C++STL的list实现

1. STL list 容器概述

list 是 C++ 标准模板库(STL)中的一个双向链表 容器。与 vectordeque 不同,list 在任意位置的插入和删除操作效率更高,但随机访问效率较低。

核心特性:

  • 双向链表结构(每个节点包含前驱和后继指针)
  • 动态内存分配,节点独立存储
  • 插入/删除时间复杂度:O(1)(已知位置)
  • 随机访问时间复杂度:O(n)

2. list 的基本使用

常用操作示例
cpp 复制代码
#include <iostream>
#include <list>

int main() {
    // 初始化
    std::list<int> lst = {1, 2, 3};

    // 插入元素
    lst.push_back(4);       // 尾部插入
    lst.push_front(0);      // 头部插入
    auto it = lst.begin();
    std::advance(it, 2);    // 移动迭代器
    lst.insert(it, 10);     // 在位置2插入10

    // 删除元素
    lst.pop_back();         // 删除尾部
    lst.pop_front();        // 删除头部
    lst.erase(it);          // 删除迭代器指向元素

    // 遍历
    for (int num : lst) {
        std::cout << num << " ";
    }
    // 输出:2 10 3
    return 0;
}

3. 手撕模拟实现 list

核心结构设计
cpp 复制代码
template <typename T>
class List {
private:
    struct ListNode {
        T data;
        ListNode* prev;
        ListNode* next;
        ListNode(const T& val, ListNode* p = nullptr, ListNode* n = nullptr)
            : data(val), prev(p), next(n) {}
    };

    ListNode* head; // 哨兵头节点
    ListNode* tail; // 哨兵尾节点
    size_t size;

public:
    // 迭代器类
    class Iterator {
    private:
        ListNode* current;
    public:
        Iterator(ListNode* node) : current(node) {}
        T& operator*() { return current->data; }
        Iterator& operator++() {
            current = current->next;
            return *this;
        }
        bool operator!=(const Iterator& other) const {
            return current != other.current;
        }
    };

    // 构造函数
    List() : size(0) {
        head = new ListNode(T());
        tail = new ListNode(T());
        head->next = tail;
        tail->prev = head;
    }

    // 析构函数
    ~List() {
        clear();
        delete head;
        delete tail;
    }

    void push_back(const T& val) {
        ListNode* newNode = new ListNode(val, tail->prev, tail);
        tail->prev->next = newNode;
        tail->prev = newNode;
        size++;
    }

    void pop_back() {
        if (size == 0) return;
        ListNode* last = tail->prev;
        last->prev->next = tail;
        tail->prev = last->prev;
        delete last;
        size--;
    }

    Iterator begin() { return Iterator(head->next); }
    Iterator end() { return Iterator(tail); }

    void clear() {
        while (head->next != tail) {
            pop_back();
        }
    }
};

4. 关键机制解析

  1. 哨兵节点

    头尾哨兵节点(head/tail)不存储数据,仅用于简化边界操作,如 begin() 指向 head->nextend() 指向 tail

  2. 迭代器设计

    封装节点指针,通过重载 operator++operator* 实现链表遍历。

  3. 插入/删除逻辑

    • 插入 :修改相邻节点的指针,例如 push_back 中:

      cpp 复制代码
      newNode->prev = tail->prev; // 新节点前驱指向原尾节点前驱
      newNode->next = tail;       // 新节点后继指向尾哨兵
      tail->prev->next = newNode; // 原尾节点前驱的后继指向新节点
      tail->prev = newNode;       // 尾哨兵前驱指向新节点
    • 删除 :调整相邻节点指针并释放内存(见 pop_back)。


5. 应用场景

  • 频繁在任意位置插入/删除(如 LRU 缓存算法)
  • 不需要随机访问的场景
  • 实现队列(std::queue 默认基于 deque,但可适配 list

总结

list 通过双向链表结构优化了插入删除效率,但牺牲了随机访问性能。理解其底层实现有助于在特定场景下合理选择容器,并加深对 STL 设计思想的理解。

相关推荐
XiaoLeisj1 分钟前
Android Kotlin 全链路系统化指南:从基础语法、类型系统与面向对象,到函数式编程、集合操作、协程并发与 Flow 响应式数据流实战
android·开发语言·kotlin·协程
dapeng28701 小时前
分布式系统容错设计
开发语言·c++·算法
qq_417695051 小时前
代码热修复技术
开发语言·c++·算法
badhope6 小时前
Mobile-Skills:移动端技能可视化的创新实践
开发语言·人工智能·git·智能手机·github
码云数智-园园7 小时前
微服务架构下的分布式事务:在一致性与可用性之间寻找平衡
开发语言
C++ 老炮儿的技术栈7 小时前
volatile使用场景
linux·服务器·c语言·开发语言·c++
hz_zhangrl7 小时前
CCF-GESP 等级考试 2026年3月认证C++一级真题解析
开发语言·c++·gesp·gesp2026年3月·gespc++一级
Liu628888 小时前
C++中的工厂模式高级应用
开发语言·c++·算法
IT猿手8 小时前
基于控制障碍函数的多无人机编队动态避障控制方法研究,MATLAB代码
开发语言·matlab·无人机·openclaw·多无人机动态避障路径规划·无人机编队
AI科技星8 小时前
全尺度角速度统一:基于 v ≡ c 的纯推导与验证
c语言·开发语言·人工智能·opencv·算法·机器学习·数据挖掘