💡 打个比方
数组是一排固定座位:大家必须挨着坐,想在前面插一个人,后面全体要往后挪。
链表是寻宝游戏:每个"节点"只藏着一份价值和一个"下一站地址",顺着地址就能找到下一个节点。
插入、删除?不用挪动任何人,只要改一行"地址"就行。
链表:用指针把一个节点一个节点串起来。每个节点存值(val)和下一节点的地址(next);head 指向第一个节点,最后一个节点的 next 是 NULL。
🖼️ 大图看明白
📏 建一条链表,只要 3 步
- 第 1 步:定义节点:struct Node { int val; Node* next; }——每个节点存一个值和"下一站地址"。
- 第 2 步:尾插:用 tail 指针记住最后一个节点;新节点建好后,让旧 tail 的 next 指向它,再把 tail 挪到新节点。
- 第 3 步:遍历:p = head,只要 p != nullptr 就输出 p->val,然后 p = p->next,一路走到 NULL 停。
为什么链表删节点这么省事?数组在头插要全体后移(O(n));链表只要让前驱的 next"跳过"它,改一行地址(O(1))。代价:链表不能直接跳到第 i 个(数组 O(1)),必须从头一个个走。
💻 C++ 怎么写
#include <iostream>
using namespace std;
struct Node { // 节点:值 + 下一站地址
int val;
Node* next;
};
int main() {
// 尾插 10、20、30
Node* head = new Node{10, nullptr};
Node* tail = head;
tail->next = new Node{20, nullptr};
tail = tail->next;
tail->next = new Node{30, nullptr};
tail = tail->next;
// 遍历:顺着 next 走,走到 NULL 停
for (Node* p = head; p != nullptr; p = p->next)
cout << p->val << " ";
cout << "\n"; // 输出:10 20 30
return 0;
}
✋ 你来试试
题目 1:删除链表中的节点 B(已知它的前驱 A),最少要改几个 next?怎么改?
只改 1 个:把 A->next 从"指向 B"改成"指向 B->next"(跳过 B)。B 自己的 next 不用管。(C++ 里还要 free / delete B 回收内存。)
题目 2:把链表 10 → 20 → 30 反转,结果是什么?说说"三指针法"的思路。
结果变成 30 → 20 → 10。三指针法:用 prev、cur、next 三个指针,先把 cur 的 next 指向 prev(掉头),再让 prev、cur 一起前进一步,逐个掉头;最后把原 head 的 next 置 NULL,并把 head 指到原尾节点。
🎯 一句话记住:链表节点 = 值 + 下一站地址;插入删除只改地址,遍历顺着 next 走到 NULL;数组会跳、链表善插删。