消除所有重复元素的出现

时间:2017-07-11 06:23:08

标签: c linked-list

我正在尝试消除链表中所有重复元素的出现。 例如,如果我有:1-2-3-2-4-2-4,我想消除所有出现的2和4并得到:1-3

我使用一个名为eliminateRepeated的函数来迭代并计算出现次数;如果计数大于1,程序将调用函数eliminateAllTheOc。但我明白了:1-3-2-4。最后一次出现没有消除。 例如,如果我单独使用值4调用函数eliminateAllOc,它可以正常工作并返回1-2-3-2-2。

typedef struct{
    int num;
}t_dataL;

typedef struct s_nodeL{
    t_dataL dataL;
    struct s_nodeL *next;
}t_nodeL;

typedef t_nodeL *t_list;

int elimnateAllTheOc(t_list *l, t_dataL *d, int(*cmp)(const void*, const void*)){
    if(!*l) return 0;
    t_nodeL *aux;
    while(*l){
        if(cmp(&(*l)->dataL, d) == 0){
            aux = *l;
            *l = (*l)->next;
            free(aux);
        }
        else l = &(*l)->next;
    }
    return 1;
}

int eliminateRepeated(t_list *l, int(*cmp)(const void*, const void*)){
    t_list *plec, *ini = l;
    t_nodeL *aux;
    int n = 0;
    while (*l){
        plec = ini;
        while(*plec){
            if(cmp(&(*l)->dataL, &(*plec)->dataL) == 0) n++;
            plec = &(*plec)->next;
        }
        if(n > 1) eliminateAllTheOc(ini, &(*l)->dataL, cmp);
        else l = &(*l)->next;
        n = 0;
    }
    return 1;
}

如何消除所有重复元素的出现?

1 个答案:

答案 0 :(得分:1)

首先,你必须修正错误的功能名称,即

int elimnateAllTheOc(...  ->  int eliminateAllTheOc(
                                      ^

然后,您必须修复代码所具有的未定义行为。问题是您将指针传递给比较值,即t_dataL *d。这是一个指向您要释放的列表元素内的数据的指针。因此,一旦释放元素,解除引用d就是未定义的行为。

示例

考虑一个非常简单的清单:

1 -> 1

在这种情况下,您要删除这两个元素。使用指向第一个元素的指针调用eliminateAllTheOc,并使用比较值将指针传递给第一个元素中的dataL

在第一个循环中释放第一个元素。因此d不再指向有效对象。因此,在您的下一个循环中,您在执行*d时会有未定义的行为。

如果要将指针传递给比较值,则必须确保指针始终指向有效对象。你可以通过复制来做到这一点:

    if(n > 1)
    {
        t_dataL tmp = (*l)->dataL;
        eliminateAllTheOc(ini, &tmp, cmp);
    }
    else l = &(*l)->next;

我怀疑这解决了代码的所有问题,但修复此UB是第一个重要步骤。