Skip to content

2016年 408 数据结构 第 2 题

数据结构2016年选择题2分

题目

已知一个带有表头结点的双向循环链表 L,结点结构为 prev|data|next,prev 和 next 分别是指向其直接前驱和直接后继结点的指针。现要删除指针 p 所指的结点,正确的语句序列是( )。

错因

A

第 1 句对:p->next->prev = p->prev 让 p 的后继的 prev 指向 p 的前驱,没问题。但第 2 句错:p->prev->next = p->prev 让 p 的前驱的 next 指向自己(前驱→前驱自环),应该指向 p 的后继。错因是写第 2 句时机械对称地照抄了第 1 句的右值 p->prev,没意识到两句的方向是相反的。

B

第 1 句错:p->next->prev = p->next 让 p 的后继的 prev 指向自己(后继→后继自环),应该指向 p 的前驱。第 2 句对。这是 A 的对称错误:选 B 的人写第 1 句时把右值错抄成了 p->next。常见的"对称对仗"心理:以为两句赋值的右值要分别配 next 和 prev,结果方向颠倒。

C

两句都错,且都让"邻居指向自己"。p->next->prev = p->next 让后继的 prev 自指,p->prev->next = p->prev 让前驱的 next 自指。错因是没理解删除的本质——把 p 的前驱和后继直接相连绕过 p。选 C 的人可能死记"修改 prev 和 next 字段",却把右值都错填成了"自己的指针",结果 p 的前后两个邻居都被搞成自环。

总解析

删除的核心思路:让 p 的前驱和后继直接相连,绕过 p,再 free(p)。

改谁改成什么含义
p->next->prevp->prev"p 后继"的前驱,应是"p 的前驱"
p->prev->nextp->next"p 前驱"的后继,应是"p 的后继"
free(p)释放 p 占用的空间,必须放在最后

为什么前两句的顺序无所谓:双向链表里 p 自身的 prev 和 next 字段一直保留到 free 之前,所以无论先改 p->next->prev 还是 p->prev->next,访问 p->prev、p->next 都不会失效。但 free(p) 必须放最后——一旦释放,再访问 p 就是悬空指针,会崩。

对比:单链表删除时由于只能向前找前驱,写法上有先后讲究;双向链表两边都能直接拿到,所以前两句顺序自由。

用图直观验证

原状态:... ↔ A(p->prev) ↔ p ↔ B(p->next) ↔ ...

操作后:... ↔ A ↔ B ↔ ...,p 被释放。

  • A 的 next 字段:原指 p,新指 B —— 即 p->prev->next = p->next
  • B 的 prev 字段:原指 p,新指 A —— 即 p->next->prev = p->prev

最终答案是 D

最后更新:

🎬 可视化演示
加载中...

提示:可在可视化区直接操作播放、步进、修改参数