板子:删除值为 x 的结点
删除结点需要知道它的前驱,所以用
pre、p两个指针一起走:删掉p时pre不动;没删时两个一起后移。
代码
void delX(LinkList L, int x) { // 删除所有值为 x 的结点
LNode *pre = L, *p = L->next; // pre 始终是 p 的前驱
while (p != NULL) {
if (p->data == x) {
pre->next = p->next; // 摘掉 p
free(p);
p = pre->next; // pre 不动,p 指向下一个待检查的结点
} else {
pre = p; // 没删:两个一起后移
p = p->next;
}
}
}
void dedupList(LinkList L) { // 有序链表去重:值相同的只留第一个
LNode *p = L->next;
if (p == NULL) return; // 空表
while (p->next != NULL) { // p 的后继存在,才有东西可比
LNode *q = p->next;
if (q->data == p->data) { // 后继和 p 相同:删掉后继,p 不动
p->next = q->next;
free(q);
} else p = q; // 不同:p 后移
}
}复杂度:时间
变形
- 删除值在
之间的结点:把 p->data == x换成p->data >= s && p->data <= t。 - 删除最小值结点:要删哪个结点得扫完才知道,所以扫的时候同时记下当前最小的结点
minp和它的前驱minpre,扫完再删。 - 无序链表去重:值域小时用辅助数组标记,见 链表按绝对值去重;否则只能对每个结点往后扫一遍,
。
易错点
- 删除后
pre不能后移:新的p还没检查过,pre仍然是它的前驱。 free(p)之后不能再访问p->next,所以要先pre->next = p->next,再free。- 顺序表里对应的是 k 计数法,见 删除所有值为 x 的元素。