从单链表中删除元素

Delete elements from singly linked list

我想从函数中的值指定的列表中删除一些元素。如果函数的 'val' 等于列表中的第一个元素,我的函数将不起作用。否则效果很好。有什么想法吗?

struct elem {
    int val;
    struct elem *next;
};

void del(struct elem *list, int val) {
    struct elem* tmp = list;
    struct elem* prev = NULL;

    while (tmp != NULL) {
        if (tmp->val == val) {
            if (prev == NULL) {
                tmp = tmp->next;
                free(list);
                list = tmp;
            } else {
                prev->next = tmp->next;
                free(tmp);
                tmp = prev->next;
            }
        } else {
            prev = tmp;
            tmp = tmp->next;
        }
    }
}

您的调用函数无法知道 list 已更新。它甚至会继续引用已被删除的同一个 list。哪个不好。

一种解决方案是将列表作为 struct elem **list:

传递
void del(struct elem **list, int val) {
    struct elem* tmp = *list;
    struct elem* prev = NULL;

    while (tmp != NULL) {
        if (tmp->val == val) {
            if (prev == NULL) {
                tmp = tmp->next;
                free(*list);
                *list = tmp;
            } else {
                prev->next = tmp->next;
                free(tmp);
                tmp = prev->next;
            }
        } else {
            prev = tmp;
            tmp = tmp->next;
        }
    }
}

编辑:还有其他解决方案。您可以 return 新列表指针:

struct elem *del(struct elem *list, int val) { ... }

你这样称呼它:

list = del(list, 12);

这个解决方案的缺点是 list 在调用中有些多余,并且省略 return 值是合法的,因此实际上不会更新列表。

我喜欢的一个解决方案是为您的列表定义一个控制结构。目前,它只包含头指针:

struct list {
    struct elem *head;
};

你对列表进行操作的函数然后将指向此结构的指针作为参数:

void del(struct list *list, int val) {
    struct elem* tmp = list->head;
    struct elem* prev = NULL;

    while (tmp != NULL) {
        if (tmp->val == val) {
            if (prev == NULL) {
                tmp = tmp->next;
                free(list->head);
                list->head = tmp;
            } else {
                prev->next = tmp->next;
                free(tmp);
                tmp = prev->next;
            }
        } else {
            prev = tmp;
            tmp = tmp->next;
        }
    }
}

struct list 可以有额外的字段,例如用于快速附加到末尾的尾指针。您还可以跟踪列表长度。