C语言单链表删除指定结点实战:含头/尾/重复值处理

纸上星河
纸上星河
发布时间:2026-10-15| 5人浏览过
原创

在C语言数据结构中,单链表的删除操作是面试与实务的核心考点。本文将通过尾插法建立链表,深入解析如何根据数值、位置以及去重需求删除结点,包含完整的C/C++代码实现与边界条件处理指南。

基于尾插法的单链表删除

使用尾插法建立的单链表,其输出顺序与输入顺序一致。以下代码演示了如何通过遍历查找指定数值并安全释放内存。

第1步:初始化链表结构

定义链表节点结构体,并创建头结点。头结点不存储实际数据,作为链表的起始标识,便于统一处理删除操作(尤其是删除第一个数据结点时)。

#include <bits/stdc++.h>
using namespace std;
typedef struct node {
    int data;
    struct node *next;
} Node; // 建议规范命名

第2步:构建单链表(尾插法)

通过循环读取用户输入,动态分配内存并链接至链表尾部。此步骤完成数据的结构化存储。

Node *head = new Node;
head->next = NULL;
Node *tail = head;

int n, k;
printf("一共要输入的数: ");
scanf("%d", &n); // 修正原稿中的换行符读取隐患
for (int i = 0; i < n; i++) {
    cin >> k;
    Node *p = new Node;
    p->data = k;
    p->next = NULL;
    tail->next = p;
    tail = p;
}

第3步:按值删除指定结点

删除操作的关键在于找到目标结点的前驱结点。由于使用了带头结点的链表,我们需要一个指针 r 指向当前结点的上一个结点,而 p 用于扫描当前结点。

  • 入口:输入待删除的值 m。
  • 动作:遍历链表,当 p->data == m 时,执行 r->next = p->next 跳过该结点,并使用 delete(p) 释放内存。
  • 注意:如果删除的是最后一个结点,后续无需再次访问 p,但循环条件已涵盖此场景。
int m;
printf("输入要删除的数: ");
scanf("%d", &m);

Node *p = head; // p从头结点开始
while (p->next != NULL) { // 标准遍历条件更稳健
    if (p->next->data == m) {
        Node *temp = p->next; // 暂存待删除结点
        p->next = temp->next; // 前驱指向后继
        delete temp;          // 释放内存
    } else {
        p = p->next; // 移动到下一个
    }
}
// 简化版逻辑(对应原稿思路):
p = head;
while (p->next != NULL) {
    if (p->next->data == m) {
        Node *q = p->next;
        p->next = q->next;
        delete(q);
    } else {
        p = p->next;
    }
}

说明:原稿代码逻辑较为特殊(在循环内判断),现代C/C++实践中通常采用“维护前驱指针”或“检查 next”的方式以避免悬空指针。上述优化代码更符合标准实践。

常见链表删除变体

删除第 i 个结点

若需按位置删除,需先定位到第 i-1 个结点。假设 i 从1开始计数且有效。

// 假设 head 为带头结点的链表
Node *p = head;
int v = 1;
while (v < i - 1 && p->next != NULL) {
    p = p->next;
    v++;
}
if (p->next != NULL) {
    Node *q = p->next;      // 第 i 个结点
    p->next = q->next;      // 跳过第 i 个
    delete(q);
}

删除与指定值 a 相同的结点(含重复值)

若链表中存在多个相同值的结点,需全部删除。此时不能使用原稿中简单的 break,必须继续遍历直到链表末尾。

int a;
scanf("%d", &a);
Node *p = head;
while (p->next != NULL) {
    if (p->next->data == a) {
        Node *q = p->next;
        p->next = q->next;
        delete(q);
    } else {
        p = p->next;
    }
}

删除链表中所有重复元素

保留第一次出现的元素,删除后续重复项。这通常需要双重循环或在单层遍历中配合哈希表(若允许额外空间)。以下为无额外空间的双层遍历解法。

Node *p = head->next;
while (p != NULL) {
    Node *q = p;
    Node *k = q->next;
    while (k != NULL) {
        if (p->data == k->data) {
            Node *temp = k;
            q->next = k->next;
            k = q->next;
            delete(temp);
        } else {
            q = k;
            k = k->next;
        }
    }
    p = p->next;
}

验证与测试案例

通过以下测试用例验证删除逻辑的正确性:

  • 测试1(删除尾部):输入 1 2 3 4 5,删除 5,输出 1 2 3 4。验证是否正确更新了尾指针前驱的 next 域并释放内存。
  • 测试2(删除头部):输入 1 2 3 4 5,删除 1,输出 2 3 4 5。验证头结点 next 是否正确指向新首元结点。
  • 测试3(删除中部):输入 1 2 3 4 5,删除 2,输出 1 3 4 5。验证中间结点的链接是否断裂后重建。

总结

单链表删除操作的精髓在于“断链”与“回收”。务必确保在释放内存之前,前驱结点的 next 指针已经正确指向了后继结点。对于涉及重复值删除的场景,需注意不要因 break 导致遗漏。以上就是C语言单链表删除指定结点的详细内容,更多关于C语言数据结构链表的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。