单链表节点结构体定义为struct Node { int val; Node* next; Node(int x) : val(x), next(nullptr) {} };插入、删除、查询操作均需严格处理空指针与边界条件,确保指针指向有效内存且连接正确。

怎么定义单链表节点结构体
单链表的核心是每个节点存数据 + 指向下一个节点的指针,C++里最直接的方式就是用 struct。别用 class 加一堆访问控制——手写实现时首要目标是清晰、可调试,不是封装。
常见错误是把 next 声明成值类型(比如 Node next),这会导致无限递归定义和栈溢出。必须是指针:Node* next。
struct Node {
int val;
Node* next;
Node(int x) : val(x), next(nullptr) {}
};
-
next初始化为nullptr,避免野指针; - 构造函数带初始化列表,防止忘记设
next; - 如果要存其他类型,后续可改用模板,但初始手写建议先固定
int,跑通逻辑再说。
怎么实现头插、尾插和按索引插入
插入操作的关键差异在「找位置」:头插不用遍历,尾插要走到最后一个节点,按索引插得先数到前一个节点。很多人卡在边界上——比如对空链表做尾插,或对长度为 1 的链表按索引 1 插入,结果访问了 nullptr->next。
统一策略:所有插入都从 head 出发,用一个临时指针 cur 遍历,但头插永远只改 head,其他插入都要停在「目标位置的前一个节点」。
- 头插:
new_node->next = head; head = new_node;; - 尾插:循环条件是
cur->next != nullptr,退出后cur是最后一个节点,再cur->next = new_node; - 按索引插入(索引从 0 开始):遍历
index - 1次,若中途cur变成nullptr,说明越界,直接返回或报错。
怎么安全地删除节点(含头删、按值删、按索引删)
删除比插入更危险,因为要释放内存,且容易出现「删完还访问」或「删了头结点但没更新 head」的问题。最常踩的坑是:遍历时用 cur = cur->next,但删的是 cur 本身,导致下一次 cur->next 访问非法地址。
正确做法是维护两个指针:prev 和 cur,删 cur 时,让 prev->next = cur->next,再 delete cur。
- 头删:单独处理,
Node* tmp = head; head = head->next; delete tmp;; - 按值删:遍历找第一个匹配的
val,删完就break,别继续删(除非明确要删所有); - 按索引删:同样遍历到
index - 1位置,检查cur->next是否为空,否则delete cur->next并重连。
怎么查节点(按索引取值、按值找位置)和避免崩溃
查询本身不改链表,但最容易触发段错误。典型错误是调用 get(5) 时链表只有 3 个节点,却没检查 cur == nullptr 就直接返回 cur->val。
所有查询函数开头必须加空指针检查,且循环中每次访问 cur->next 前,先确认 cur 不为空。返回值设计也要明确:按索引取值失败时返回什么?-1?抛异常?手写阶段建议返回特殊值(如 INT_MIN)并加注释说明。
-
get(index):循环index次,每次先判cur == nullptr,再走cur = cur->next; -
find(val):返回索引而非指针,便于调试;找不到就返回-1; - 不要在查询函数里
delete或改next,那是删除函数的事。
手写单链表真正难的不是语法,而是每一步操作前后,head 和所有 next 指针是否都指向有效内存、有没有漏掉 nullptr 判断、删节点后有没有彻底断开连接。写完务必用空链表、单节点、两节点三类 case 手动 trace 一遍指针走向。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











