Appearance
题目
已知带头结点的非空单链表 L 的头指针为 h,指针 p 指向 L 中间的一个链表结点(不是第一个和最后一个结点)。q=p->next,p->next=q->next,q->next=h->next,h->next=q。这段代码的功能是()。
错因
A
只看第一句 q = p->next,认为 q 既然是 p 的后继,那代码就是"把 q 留在 p 后面"。忽略了第二条语句 p->next = q->next 恰恰是在把 q 从 p 后面摘下来——执行完这一步,p 直接跳过 q 去连后面的结点,q 已经不在 p 之后了。
B
把"修改 p 的 next 指针"误读成"移动 p 这个结点"。整段代码里 p 自身的位置和被指向情况从头到尾没有改变(没有任何语句写 ?->next = p),变化的只是 p 的 next 指针指向了更后面的结点。p 始终原地不动。
C
混淆了最后两步。第三、四句把 q(不是 p)插到 h 的后面:q->next = h->next 让 q 接管 h 原来的后继,h->next = q 让 h 指向 q。这里全程没有出现"h 指向 p"或"p 接到 h 之后"的语句,被插入到 h 后面的是 q 而不是 p。
总解析
按顺序逐句翻译四条语句的语义:
q = p->next:把 q 设为 p 的直接后继(先把这个结点的引用记下来,准备搬走它)。p->next = q->next:p 越过 q,直接连到 q 原来的下一个结点。q 从 p 之后被摘出,但 q 自己仍然指向原来的后继。q->next = h->next:把 q 的 next 改为指向 h 原来的第一个数据结点。这一步让 q 准备好"接到 h 后面"——它的后继被改成原来链表的头。h->next = q:h 的 next 指向 q。q 正式成为 h 之后的第一个数据结点。
净效果:q 这一个结点从 p 的后面被摘下,搬到了头结点 h 的正后方,相当于一次"摘除 + 头插"。
链表前后对比(设原链表为 h → … → p → q → r → …):
- 操作前:
h → A → B → … → p → q → r → … - 操作后:
h → q → A → B → … → p → r → …
q 移动到了 h 之后,A 仍是原来 h 之后的第一个结点(现在变成了 q 的后继),p 直接连到了 r。
最终答案是 D。