You need to enable JavaScript to run this app. C语言链表按值出现次数阈值删除节点的实现及段错误修复
优惠活动
大模型
产品
解决方案
定价
更多

C语言链表按值出现次数阈值删除节点的实现及段错误修复

触发段错误的核心问题
  • 标识符拼写偏差:代码中多处使用未定义的变量、函数名,比如deleteOccurrences内误用不存在的Lista、testa标识符,countOccurrences循环内错写head = testa->next,调用统计函数时将countOccurrences少写一个字母变成countOccurences,这类错误会直接造成非法内存访问。
  • 指针传递失效:manageList目前直接接收头指针的值,内部调用删除函数时取的是函数局部指针的地址,修改结果完全无法传回main函数;如果链表头节点本身需要被删除,main内的头指针依然会指向已经被释放的内存块,触发野指针访问。
  • 遍历逻辑漏洞:原manageList的循环中,删除操作完成后直接执行head = head->next,如果当前节点就是被删除的目标,就会访问已经被释放的节点内存;同时重复遍历统计的逻辑冗余,还会因为前面的删除操作破坏链表结构,导致后续遍历越界。
修正实现方案

调整后的执行逻辑完全匹配需求,从根源上避免上述问题:

  1. 逐节点校验值的出现次数,达到阈值就删除所有该值的节点
  2. 所有涉及链表头修改的操作,传入头指针的地址,保证修改结果同步到调用方
  3. 每完成一次删除操作,重置遍历起点到链表头,避免因为链表结构变化导致的遍历错位
可运行的完整修正代码
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// 节点定义
typedef struct El{
    int val;
    struct El *next;
}ElemList;

typedef ElemList *List;

// 头插法实现,与原有逻辑一致
List insert(List head, int val) {
    ElemList *new_node = (ElemList*)malloc(sizeof(ElemList));
    new_node->val = val;
    new_node->next = head;
    return new_node;
}

// 统计指定值在链表中的出现次数
int countOccurrences(List head, int val) {
    int count = 0;
    while(head != NULL) {
        if(head->val == val) {
            count++;
        }
        head = head->next;
    }
    return count;
}

// 删除链表中所有值为val的节点,传入头指针地址保证头节点可修改
void deleteOccurrences(List *head, int val) {
    ElemList *temp = *head, *prev = NULL;
    // 处理连续为目标值的头节点
    while(temp != NULL && temp->val == val) {
        *head = temp->next;
        free(temp);
        temp = *head;
    }
    // 处理链表中间的目标值节点
    while(temp != NULL) {
        while(temp != NULL && temp->val != val) {
            prev = temp;
            temp = temp->next;
        }
        if(temp == NULL) return;
        prev->next = temp->next;
        free(temp);
        temp = prev->next;
    }
}

// 链表管理逻辑,支持可配置的删除阈值
void manageList(List *head, int threshold) {
    ElemList *cur = *head;
    while(cur != NULL) {
        int current_val = cur->val;
        int occur_count = countOccurrences(*head, current_val);
        // 达到阈值就删除所有该值的节点
        if(occur_count >= threshold) {
            deleteOccurrences(head, current_val);
            // 删除完成后重置遍历起点到链表头,避免错位
            cur = *head;
        } else {
            cur = cur->next;
        }
    }
}

// 打印链表工具函数
void printList(List head) {
    while(head != NULL) {
        printf("%d", head->val);
        if(head->next != NULL) printf("->");
        head = head->next;
    }
    printf("\n");
}

int main() {
    List head = NULL;
    // 头插法构建目标链表,最终顺序为1->3->8->5->6->8->3->8->9
    head = insert(head,9);
    head = insert(head,8);
    head = insert(head,3);
    head = insert(head,8);
    head = insert(head,6);
    head = insert(head,5);
    head = insert(head,8);
    head = insert(head,3);
    head = insert(head,1); 

    printf("原链表:");
    printList(head);
    manageList(&head, 3);
    printf("阈值≥3删除后链表:");
    printList(head);
    return 0;
}
运行效果验证

按照示例场景,值为8的节点共出现3次,达到删除阈值会被全部移除,最终输出的链表为1->3->5->6->3->9,与需求预期完全一致。

性能优化提示:如果链表存储的数值范围较大,可以把逐次调用计数函数的逻辑替换为首轮全链表遍历,用哈希表一次性统计所有值的出现次数,减少重复遍历的性能开销。

内容的提问来源于stack exchange,提问作者Marco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 10:45:10