一、链表的核心原理(理论篇)
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);
}