You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现有序链表merge函数时出现垃圾值/段错误,求技术排查

排查有序链表合并时的数组垃圾值/段错误问题

我来帮你梳理下代码里的问题,顺便给你两种可行的解决方案:

你的代码里的核心问题

1. 未完成的合并循环导致数组存垃圾值

你代码最后那段while(leftpos<=m...没写完,这会让newarr后半部分的元素没被正确赋值,还是内存里的随机垃圾值,打印的时候自然会出问题。

2. 没把排序后的数组写回链表

就算你补完了循环,当前代码也没把newarr里的排序后的值放回链表节点,等于白做了数组排序,链表还是原来的无序状态。

3. 变长数组的栈溢出风险

你用的int arr[len];是C99的变长数组,如果链表节点数太多,栈空间不够就会触发段错误,不如用动态分配的数组更稳妥。

4. 没必要的数组转换逻辑

既然两个输入链表本身就是有序的,直接操作链表节点合并才是最高效的,完全没必要转成数组再折腾,既浪费内存又容易出错。


修复后的数组转换版本代码

如果你坚持要保留数组转换的思路,这是补全并修复后的完整代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct _node { int data; struct _node * next; } node_t; 
typedef struct { node_t * head; node_t * tail; } LL_t; 

LL_t* createList(int num_nodes); 
void printList(LL_t* L); 

void merge(LL_t * L, LL_t * L2){ 
    if(L2->head == NULL){ // 处理L2为空的情况
        free(L2); 
        return; 
    } 
    else if(L->head == NULL){ // 处理L1为空的情况
        *L = *L2; 
        free(L2); 
        return; 
    } 

    // 计算L1的最后一个节点索引mid
    node_t* node = L->head;
    int mid = 0;
    while (node->next != NULL) {
        mid++;
        node = node->next;
    }
    // 连接两个链表
    L->tail->next = L2->head; 
    L->tail = L2->tail; 

    // 统计总节点数
    int len = 0;
    node_t* ind = L->head;
    while (ind != NULL) {
        len++;
        ind = ind->next;
    }

    // 动态分配数组,避免栈溢出
    int* arr = (int*)malloc(len * sizeof(int));
    int* newarr = (int*)malloc(len * sizeof(int));
    if (!arr || !newarr) {
        // 内存分配失败的容错处理
        free(arr);
        free(newarr);
        free(L2);
        return;
    }

    // 将链表元素存入数组arr
    node_t* cur = L->head;
    for(int i = 0; cur != NULL; i++){ 
        arr[i] = cur->data; 
        cur = cur->next; 
    } 

    // 归并两个有序子数组到newarr
    int leftpos = 0;
    int rightpos = mid + 1;
    int newpos = 0;

    // 合并两个有序段
    while(leftpos <= mid && rightpos <= len - 1){ 
        if(arr[leftpos] < arr[rightpos]){ 
            newarr[newpos++] = arr[leftpos++]; 
        } else {
            newarr[newpos++] = arr[rightpos++]; 
        }
    } 
    // 填充左半部分剩余元素
    while(leftpos <= mid){
        newarr[newpos++] = arr[leftpos++];
    }
    // 填充右半部分剩余元素
    while(rightpos <= len - 1){
        newarr[newpos++] = arr[rightpos++];
    }

    // 将排序后的数组写回链表
    cur = L->head;
    for(int i = 0; cur != NULL; i++){
        cur->data = newarr[i];
        cur = cur->next;
    }

    // 释放动态分配的内存和L2结构体
    free(arr);
    free(newarr);
    free(L2);
}

更高效的链表直接合并方案

这是处理有序链表合并的标准解法,直接操作节点,时间复杂度O(n+m),空间复杂度O(1),完全避开数组相关的问题:

void merge(LL_t * L, LL_t * L2){ 
    if(L2->head == NULL){ // L2为空,直接释放
        free(L2); 
        return; 
    } 
    else if(L->head == NULL){ // L1为空,直接接管L2的内容
        *L = *L2; 
        free(L2); 
        return; 
    } 

    // 用dummy节点简化头节点的处理逻辑
    node_t dummy;
    dummy.next = NULL;
    node_t* current = &dummy;

    node_t* p1 = L->head;
    node_t* p2 = L2->head;

    // 逐个比较两个链表的节点,选择较小的接入结果
    while(p1 != NULL && p2 != NULL){
        if(p1->data < p2->data){
            current->next = p1;
            p1 = p1->next;
        } else {
            current->next = p2;
            p2 = p2->next;
        }
        current = current->next;
    }

    // 接入剩余的节点
    if(p1 != NULL){
        current->next = p1;
    } else {
        current->next = p2;
        L->tail = L2->tail; // 如果剩余的是L2的节点,更新L的尾指针
    }

    // 更新L的头指针
    L->head = dummy.next;

    // 释放L2的结构体(注意:L2的节点已经合并到L中,不能释放节点)
    free(L2);
}

小提示

如果是刷题或者实际项目中,优先用链表直接合并的方案,不仅效率更高,还能避免数组带来的各种内存问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:54:19