Bootstrap

链表数据结构:从零开始的C++实现完全指南(教学版)

一、链表的核心原理(理论篇)

1.1 链表的数学本质

链表可以看作是一个递归定义的序列结构:

List = Empty | Node(data, List)
  • Empty:空链表(基础情形)
  • Node:包含数据元素和子链表的节点(递归情形)

示例推导

List1 = Node(5, Empty)
List2 = Node(3, List1) → Node(3, Node(5, Empty))
List3 = Node(1, List2) → Node(1, Node(3, Node(5, Empty)))

1.2 内存结构详解

每个节点在内存中的存储方式:

+----------------+-----------------+
| 数据区(sizeof(T)) | 指针区(sizeof(void*)) |
+----------------+-----------------+

假设存储int类型数据(4字节),在64位系统下:

+----+--------+
| 5  | 0xABCD | → 每个节点占用12字节(4+8)
+----+--------+

1.3 指针操作的原子性

每个链表操作本质是对指针的精确控制,以插入操作为例:

插入新节点N到A和B之间

初始状态:
A → B → C

步骤分解:
1. 创建新节点N(内存地址0x1234)
2. 将N的next指向B:N->next = A->next
3. 将A的next指向N:A->next = N

最终状态:
A → N → B → C

二、单链表实现详解(实践篇)

2.1 节点类的完整实现

template <typename T>
struct ListNode {
   
    T data;         // 数据域(存储用户数据)
    ListNode* next; // 指针域(存储下个节点地址)
    
    // 构造函数:严格初始化每个成员
    explicit ListNode(const T& val)
        : data(val),       // 初始化数据域
          next(nullptr) {
    // 指针初始化为空
        // 验证数据有效性(可选)
        if constexpr (std::is_arithmetic_v<T>) {
   
            if (std::isnan(val)) throw std::invalid_argument("NaN not allowed");
        }
    }

    // 禁用拷贝构造函数(防止意外复制)
    ListNode(const ListNode&) = delete;
    ListNode& operator=(const ListNode&) = delete;
};

2.2 链表类的完整生命周期管理

template <typename T>
class LinkedList {
   
private:
    ListNode<T>* head; // 头指针(链表入口)
    size_t count;      // 节点计数器

public:
    // 构造函数:初始化空链表
    LinkedList() noexcept 
        : head(nullptr), count(0) {
   
        // 确保初始状态正确
        assert(head == nullptr && count == 0);
    }

    
;