🔗

链表基础

数组是一排座位,链表是一张寻宝地图

💡 打个比方

数组是一排固定座位:大家必须挨着坐,想在前面插一个人,后面全体要往后挪。

链表是寻宝游戏:每个"节点"只藏着一份价值和一个"下一站地址",顺着地址就能找到下一个节点。

插入、删除?不用挪动任何人,只要改一行"地址"就行。

链表:用指针把一个节点一个节点串起来。每个节点存值(val)和下一节点的地址(next);head 指向第一个节点,最后一个节点的 next 是 NULL。

🖼️ 大图看明白

链表的节点:值 + "下一站地址" next(原指针) 新指针 head ① 串起来:head 指向头节点,节点用 next 手拉手 head 10 → 20 → 30 NULL 走到 next = NULL 就结束 ② 删除:前驱节点直接"跳过"被删节点 删前 10 → 20 → 30 NULL 删除 B 删后 10 → A 的 next 直接指向 C 20 B 被删掉 30 NULL ③ 反转:所有箭头方向反过来 反转前 10 → 20 → 30 NULL 反转 反转后 30 → 20 → 10 NULL 新 head 指向原来的尾节点;原 head 的 next 要置 NULL

📏 建一条链表,只要 3 步

  1. 第 1 步:定义节点:struct Node { int val; Node* next; }——每个节点存一个值和"下一站地址"。
  2. 第 2 步:尾插:用 tail 指针记住最后一个节点;新节点建好后,让旧 tail 的 next 指向它,再把 tail 挪到新节点。
  3. 第 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;数组会跳、链表善插删。