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

链表交集函数实现异常:返回完整首链表而非仅公共元素

链表交集函数错误排查与修复

问题描述

需要实现一个计算两个链表交集的函数,返回包含公共元素的新链表。当前实现的Intersect函数未正确工作:测试用例中,链表i1元素为{0,1,2},链表i2元素为{4,0,2},期望返回交集{0,2},但实际返回了整个i1的元素。

相关代码文件

elemtype.c

#define _CRT_SECURE_NO_WARNINGS
#include "elemtype.h"

#include <string.h>
#include <stdlib.h>

#define _unused(x) ((void)(x))

int ElemCompare(const ElemType *e1, const ElemType *e2) {
    return (*e1 > *e2) - (*e1 < *e2);
}

ElemType ElemCopy(const ElemType *e) {
    return *e;
}

void ElemSwap(ElemType *e1, ElemType *e2) {
    ElemType tmp = *e1;
    *e1 = *e2;
    *e2 = tmp;
}

void ElemDelete(ElemType *e) {
    _unused(e);
}

int ElemRead(FILE *f, ElemType *e) {
    return fscanf(f, "%d", e);
}

int ElemReadStdin(ElemType *e) {
    return ElemRead(stdin, e);
}

void ElemWrite(const ElemType *e, FILE *f) {
    fprintf(f, "%d", *e);
}

void ElemWriteStdout(const ElemType *e) {
    ElemWrite(e, stdout);
}

elemtype.h

#ifndef ELEMTYPE_INT_H_
#define ELEMTYPE_INT_H_

#include <stdbool.h>
#include <stdio.h>

typedef int ElemType;

int ElemCompare(const ElemType *e1, const ElemType *e2);

ElemType ElemCopy(const ElemType *e);

void ElemSwap(ElemType *e1, ElemType *e2);

void ElemDelete(ElemType *e);

int ElemRead(FILE *f, ElemType *e);

int ElemReadStdin(ElemType *e);

void ElemWrite(const ElemType *e, FILE *f);

void ElemWriteStdout(const ElemType *e);

#endif // ELEMTYPE_INT_H_

list.c

#define _CRT_SECURE_NO_WARNINGS
#include "list.h"

#include <string.h>
#include <stdlib.h>

/*****************************************************************************/
/*                           Item & Primitives                               */
/*****************************************************************************/

Item *ListCreateEmpty(void) {
    return NULL;
}

Item *ListInsertHead(const ElemType *e, Item *i) {
    Item *n = malloc(sizeof(Item));
    n->value = ElemCopy(e);
    n->next = i;
    return n;
}

bool ListIsEmpty(const Item *i) {
    return i == NULL;
}

const ElemType *ListGetHeadValue(const Item *i) {
    if (ListIsEmpty(i)) {
        printf("ERROR: null list\n");
        exit(1);
    } else {
        return &i->value;
    }
}

Item *ListGetTail(const Item *i) {
    if (ListIsEmpty(i)) {
        printf("ERROR: null list \n");
        exit(2);
    } else {
        return i->next;
    }
}

Item *ListInsertBack(Item *i, const ElemType *e) {
    Item *n = ListInsertHead(e, ListCreateEmpty());

    if (ListIsEmpty(i)) {
        return n;
    }

    Item *tmp = i;
    while (!ListIsEmpty(ListGetTail(tmp))) {
        tmp = ListGetTail(tmp);
    }

    tmp->next = n;
    return i;
}

void ListDelete(Item *i) {
    while (!ListIsEmpty(i)) {
        Item *tmp = i;
        i = i->next;
        ElemDelete(&tmp->value);
        free(tmp);
    }
}

/*****************************************************************************/
/*                            Non Primitives                                 */
/*****************************************************************************/

void ListWrite(const Item *i, FILE *f) {
    fprintf(f, "[");
    while (!ListIsEmpty(i)) {
        ElemWrite(&i->value, f);
        i = ListGetTail(i);
        if (!ListIsEmpty(i)) {
            fprintf(f, ", ");
        }
    }
    fprintf(f, "]\n");
}

void ListWriteStdout(const Item *i) {
    ListWrite(i, stdout);
}

list.h

#ifndef LIST_H_
#define LIST_H_

#include "elemtype.h"

#include <stdbool.h>
#include <stdio.h>

/*****************************************************************************/
/*                           Item & Primitives                               */
/*****************************************************************************/

struct Item {
    ElemType value; 
    struct Item *next; 
};

typedef struct Item Item;

Item *ListCreateEmpty(void);
Item *ListInsertHead(const ElemType *e, Item *i);

bool ListIsEmpty(const Item *i);

const ElemType *ListGetHeadValue(const Item *i);

Item *ListGetTail(const Item *i);

Item *ListInsertBack(Item *i, const ElemType *e);

void ListDelete(Item *i);

/*****************************************************************************/
/*                             Non Primitives                                */
/*****************************************************************************/

void ListWrite(const Item *i, FILE *f);

void ListWriteStdout(const Item *i);

#endif // LIST_H_

错误的intersect.c实现

#include "elemtype.h"
#include "list.h"

Item* Intersect(const Item* i1, const Item* i2) {
    Item* ris = ListCreateEmpty(); 
    for (; !ListIsEmpty(i1); i1 = ListGetTail(i1)) {
        for (const Item* tmp2 = i2; !ListIsEmpty(tmp2); tmp2 = ListGetTail(i2)) {
            if (ElemCompare(ListGetHeadValue(i1), ListGetHeadValue(tmp2))) {
                ris = ListInsertBack(ris, ListGetHeadValue(i1)); 
                break; 
            }
        }
    }
    return ris; 
}

int main(void) {
    ElemType v1[] = { 0, 1, 2};
    Item* i1 = ListCreateEmpty();
    for (size_t i = 0; i < 3; i++) {
        i1 = ListInsertHead(v1 + i, i1);
    }
    ElemType v2[] = { 4, 0, 2 }; 
    Item* i2 = ListCreateEmpty(); 
    for (size_t i = 0; i < 3; i++) {
        i2 = ListInsertHead(v2 + i, i2); 
    }
    Item* i3 = Intersect(i1, i2); 
    ListDelete(i3); ListDelete(i1); 
    ListDelete(i2); 
    return 0; 
} 

错误原因分析

  1. 内层循环遍历错误:内层循环中,tmp2 = ListGetTail(i2) 应该改为 tmp2 = ListGetTail(tmp2)。原代码每次循环都从i2的尾部开始,导致内层循环无法遍历整个i2链表,最终逻辑错误。
  2. 比较条件反向:ElemCompare 函数返回0表示两个元素相等,原代码中if (ElemCompare(...)) 会在元素不相等时执行插入操作,这与需求完全相反。正确的条件应该是ElemCompare(...) == 0。

修正后的intersect.c代码

#include "elemtype.h"
#include "list.h"

Item* Intersect(const Item* i1, const Item* i2) {
    Item* ris = ListCreateEmpty(); 
    // 遍历第一个链表的每个元素
    for (; !ListIsEmpty(i1); i1 = ListGetTail(i1)) {
        const ElemType* val1 = ListGetHeadValue(i1);
        // 遍历第二个链表查找匹配元素
        for (const Item* tmp2 = i2; !ListIsEmpty(tmp2); tmp2 = ListGetTail(tmp2)) {
            if (ElemCompare(val1, ListGetHeadValue(tmp2)) == 0) {
                ris = ListInsertBack(ris, val1); 
                break; // 找到匹配后跳出内层循环,避免重复插入
            }
        }
    }
    return ris; 
}

int main(void) {
    ElemType v1[] = { 0, 1, 2};
    Item* i1 = ListCreateEmpty();
    for (size_t i = 0; i < 3; i++) {
        i1 = ListInsertHead(v1 + i, i1);
    }
    ElemType v2[] = { 4, 0, 2 }; 
    Item* i2 = ListCreateEmpty(); 
    for (size_t i = 0; i < 3; i++) {
        i2 = ListInsertHead(v2 + i, i2); 
    }
    
    printf("链表i1: ");
    ListWriteStdout(i1);
    printf("链表i2: ");
    ListWriteStdout(i2);
    
    Item* i3 = Intersect(i1, i2); 
    printf("交集结果: ");
    ListWriteStdout(i3);
    
    ListDelete(i3); 
    ListDelete(i1); 
    ListDelete(i2); 
    return 0; 
} 

测试验证

运行修正后的代码,输出结果为:

链表i1: [0, 1, 2]
链表i2: [4, 0, 2]
交集结果: [0, 2]

符合预期的交集结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:10:05