Appearance
题目
设有一个双向链表 L,结构为 [p2, p1],头结点为 head。初始时 head = cu。现要将每个结点的 p2 指向 p1 指向结点的直接后继,应该进行的操作是()。
错因
A
直接套了"双向链表遍历"模板,没有边界检查。当 cu 走到尾结点时 cu->p1 == NULL,再访问 cu->p1->p1 就是空指针解引用,运行时崩溃。
B
循环条件用 cu->p2 != NULL 来挡边界,但字段选错了——p2 是要修改的辅助字段,它的取值是循环要"写"的目标,不能用来判断"是否到了尾结点";判断尾结点应该看 p1(即 next)。此外,这种写法会在 p2 已经是 NULL 的结点直接跳出,这些结点的 p2 不会被赋成正确的"下下个",违反题目"每个结点的 p2 都要指向 p1 指向结点的直接后继"的要求。
C
if (cu->p1 != NULL) 看似挡住了空指针访问,但致命的死循环:cu = cu->p1 写在 if 块内部,没有 else 分支。一旦走到尾结点(cu->p1 == NULL),程序进入"什么也不做"的隐式 else,cu 永远不再推进,循环卡在尾结点反复判断、永不退出。此外,尾结点的 p2 也没有被处理(应当为 NULL,因为它没有"下下个结点")。
总解析
先读懂题:每个结点有两个指针字段 p1 和 p2,其中 p1 是双向链表的"指向直接后继"指针(即 next),p2 是要被赋值的辅助指针。需求是 cu->p2 = cu->p1->p1,即让 p2 指向"下下个结点"。
关键边界:当 cu 是尾结点时,cu->p1 == NULL,没有"下下个结点",应令 cu->p2 = NULL。
正确实现必须同时满足三点:
- 进入
cu->p1->p1之前必须判断cu->p1 != NULL,否则空指针崩溃; - 尾结点不能跳过——它的
p2应被显式置为 NULL; cu = cu->p1必须放在 if/else 之外(即不论是否进入 if,都要推进),否则尾结点上死循环。
逐项核对:
- A ✗ 缺第 1 条边界检查,尾结点会触发空指针解引用。
- B ✗ 把判断字段误用为
p2,并且把"应该被赋值"的结点提前放过去了。 - C ✗ 满足第 1 条,但违反第 2、3 条——推进语句被困在 if 里,且尾结点 p2 未置 NULL。
- D ✓ 三条都满足:
if里赋值"下下个",else把尾结点p2置 NULL,cu = cu->p1在 if/else 之外,能在尾结点这一轮做完赋值后把cu推进到 NULL,正常退出。
最终答案是 D。
编者注(生僻术语):题干 "结构为 [p2, p1]" 是原题对结点字段的简写表示(结点中含
p2和p1两个指针字段);"初始时 head = cu" 在 C 语义里赋值方向看似反了,但按上下文应理解为"用cu从 head 开始遍历"——本题保留原题原文,不做改动。p1实际承担常规的"指向直接后继 (next)"职责,p2是题目要求的辅助指针。