链表题:一个带头节点的非空单循环链表(2021年选择)

已知头指针 h 指向一个带头节点的非空单循环链表,节点结构为:
data next
其中,next 是指向直接后继节点的指针,p 是尾指针,q 是临时指针。现要删除该
链表的第一个元素,正确的语句序列是______。
A. h->next=h->next->next; q = h->next; free(q);
B. q = h->next; h->next = h->next->next; free(q);
C. q = h->next; h->next = q-> next; if(p!=q)p=h; free(q);
D. q = h->next; h->next = q->next; if(p==q)p=h; free(q);

题目分析

  1. 链表结构

    • 链表为带头节点的单循环链表,头指针 h 指向头节点(头节点本身不存储数据)。
    • 第一个实际数据节点为 h->next
    • 尾指针 p 指向链表的最后一个节点(即 p->next == h)。
    • 需要删除链表的第一个元素(即头节点的直接后继节点)。
  2. 删除操作的核心逻辑

    • 删除第一个元素需要:
      1. 保存待删除节点q = h->next)。
      2. 调整头节点的 next 指针,使其指向第二个节点(h->next = q->next)。
      3. 处理尾指针 p(若被删除的节点是最后一个节点,需将 p 指向头节点)。
      4. 释放内存free(q))。

选项逐项分析

选项A:h->next=h->next->next; q = h->next; free(q);

  • 错误原因
    • 先修改 h->next,使头节点指向第二个节点,此时 q = h->next 保存的是新的第一个节点(原第二个节点)。
    • 最后释放的是新的第一个节点(原第二个节点),而非原第一个节点。
    • 逻辑错误:实际删除的是第二个节点,而非第一个节点。

选项B:q = h->next; h->next = h->next->next; free(q);

  • 错误原因
    • 虽然正确删除了第一个节点(保存 q = h->next,调整 h->next = q->next,释放 q),但未处理尾指针 p
    • 特殊情况错误
      • 若链表只有一个数据节点(即 h->next == p),删除后链表仅剩头节点,此时尾指针 p 应指向头节点 h
      • 但选项B未更新 p,导致 p 仍指向被释放的节点(悬空指针),后续操作可能崩溃。

选项C:q = h->next; h->next = q->next; if(p!=q)p=h; free(q);

  • 错误原因
    • if(p!=q)p=h; 逻辑错误。
    • 正确逻辑:若被删除的节点是尾节点(即 p == q),才需要将 p 指向头节点 h
    • 选项C的条件是 p != q 时设置 p = h,与实际需求相反。

选项D:q = h->next; h->next = q->next; if(p==q)p=h; free(q);

  • 正确性分析
    1. 保存待删除节点q = h->next(正确保存第一个数据节点)。
    2. 调整头节点的 next 指针h->next = q->next(正确指向第二个节点)。
    3. 处理尾指针 p
      • 若被删除的节点是尾节点(即 p == q),说明链表只剩头节点,此时将 p 指向头节点 hif(p==q)p=h;)。
    4. 释放内存free(q)(正确释放原第一个节点)。
  • 覆盖所有情况
    • 链表有多个节点:删除后,p 仍指向原最后一个节点。
    • 链表仅一个节点:删除后,p 被更新为 h,链表仍保持循环结构。

总结

  • 核心操作
    1. 保存待删除节点(q = h->next)。
    2. 调整头节点指针(h->next = q->next)。
    3. 处理尾指针(若 p == q,则 p = h)。
    4. 释放节点内存(free(q))。
  • 选项D是唯一同时满足正确删除逻辑和尾指针处理的答案。

 再次梳理

  1. 头指针h与头节点的关系

    • 头节点是一个实际存在的节点,但通常不存储有效数据(或存储链表元数据)。
    • 头指针h是一个指针变量,存储的是头节点的内存地址,即 h 指向头节点。
    • 首节点(第一个数据节点)通过头节点的 next 指针访问,即 h->next
    • 错误理解纠正:首节点是 h->next,而不是 h->next->next。后者是首节点的下一个节点。
  2. 删除第一个元素的步骤

    • Step 1:保存待删除节点(首节点):q = h->next;
    • Step 2:调整头节点的 next 指针,绕过首节点:h->next = q->next;
    • Step 3:处理尾指针 p
      • 若被删除的节点是尾节点(即 p == q),说明链表原本只有一个数据节点,删除后链表为空,需将 p 指向头节点:if(p == q) p = h;
    • Step 4:释放首节点内存:free(q);
  3. 选项D的正确性验证

    c复制代码

    q = h->next;          // Step 1: 保存首节点
    h->next = q->next;    // Step 2: 头节点指向第二个节点(或头节点自身,若链表仅一个数据节点)
    if(p == q) p = h;     // Step 3: 若删除的是尾节点,更新p指向头节点
    free(q);              // Step 4: 释放首节点
    • 覆盖所有情况
      • 链表有多个节点:删除后,p 仍指向原尾节点,链表保持循环。
      • 链表仅一个节点:删除后,p 被更新为 h,链表仅剩头节点,依然循环。
  4. 其他选项错误分析

    • 选项B:未处理尾指针 p,若删除最后一个节点会导致 p 悬空。
    • 选项C:条件 if(p != q) 错误,应为 if(p == q)
    • 选项A:操作顺序错误,导致误删第二个节点。

答案:D. q = h->next; h->next = q->next; if(p==q)p=h; free(q);

图示辅助理解:

复制代码

原链表结构:
h(头节点) -> 数据节点1(首节点) -> 数据节点2 -> ... -> 尾节点p -> h

删除首节点后:
h(头节点) -> 数据节点2 -> ... -> 尾节点p -> h

若原链表仅一个数据节点:
h(头节点) -> 数据节点1(p指向此处) -> h

删除后:
h(头节点) -> h(此时p需更新为h)

 

你可能感兴趣的:(数据结构,数据结构,链表)