NOTICE: 本题代码是按照源码顺序贴上的,复制可直接运行
环境: Visual Stdio Code
题目
已知单链表 A, B 和 C 均为递增有序排列,现要求对 A 表作如下操作:删去那些既在 B 表中出现又在 C 表中出现的元素。试对单链表编写实现上述操作的算法。
分析
题目的要求我们可以理解成将三个单链表的交集从表 A 中删除,A 中剩余元素就是结果。
我们可以分成两大部分:第一部分,找交集;第二部分,删除节点并释放其内存空间。
可以细分一下找交集的步骤:两两对比,即:先找 B 和 C 中的相等元素,再找 B 和 A 中相等的元素,如果两个条件(元素 x 既在 B 和 C 中,又同时在 A 中)都满足,就删除该元素所在节点。
代码:
初始化:
#include<stdlib.h>
#include<stdio.h>
#define ERROR 0
#define OK 1
typedef int ElemType;
typedef int Status;
typedef struct LNode
{
ElemType data;
LNode *next;
}LNode, *LinkList;
Status InitList(LinkList &L)
{ // 初始化单链表 L
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
return OK;
}//InitList
创建单链表:
Status CreateList(LinkList &L, int e)
{ // 创建单链表
LinkList p = L;
while(p->next)
p = p->next;
LinkList temp = (LinkList)malloc(sizeof(LNode));
temp->data = e;
temp->next = NULL;
p->next = temp;
return OK;
}//CreateList
打印单链表:
Status DispList(LinkList &L)
{ // 打印单链表 L
LinkList p = L;
p = p->next;
while(p)
{
printf("%d\t", p->data);
p = p->next;
}
return OK;
}//DispList
找交集(即:删除次要节点):
Status ListMinus(LinkList &A, LinkList &B, LinkList &C)
{ // 求交集
LinkList pa, qa, pb, pc, temp;
pa = A; qa = pa; pa = pa->next; // pa 为 qa 的直接后继节点
pb = B->next; // pb 和 pc 分别指向 B 和 C 的首元结点
pc = C->next;
while(pa && pb && pc) // 如果有一个链表遍历完毕,就跳出循环,这样可以缩短运行时间
{
if(pa->data == pb->data && pb->data == pc->data) // 删除条件
{
temp = pa;
pa = pa->next;
qa->next = qa->next->next; // 可以写成 qa->next = pa;
pb = pb->next;
pc = pc->next;
free(temp);
}
else if(pb->data < pc->data) // 如果 pb 小于 pc 就将 pb 和 pa、qa 后移
{
pa = pa->next; // 因为 pa->data != pb->data
qa = qa->next;
pb = pb->next;
}
else if(pb->data > pc->data) // 如果 pb 小于 pc 反之后移 pc 和 pa 、qa
{
pa = pa->next;
qa = qa->next;
pc = pc->next;
}
else if(pa->data < pb->data) // 如果 pa 小于 pb 就将 pa、qa 后移
{
pa = pa->next;
qa = qa->next;
}
else if(pa->data == pa->next->data) // 如果 A 中有重复元素
{
pa = pa->next;
qa = qa->next;
}
}
return OK;
}//ListMinus
主函数:
int main()
{
LinkList A, B, C;
// 初始化
InitList(A); InitList(B); InitList(C);
// 创建
printf("\n表 A 为:\n");
for(int i = 1; i < 6; i++)
CreateList(A, i);
DispList(A);
printf("\n表 B 为:\n");
for(int j = 2; j < 7; j++)
CreateList(B, j);
DispList(B);
printf("\n表 C 为:\n");
for(int k = 3; k < 9; k++)
CreateList(C, k);
DispList(C);
// 取交集
ListMinus(A, B, C);
printf("\n表 A 为:\n");
DispList(A);
return OK;
}
运行结果示意图:
详细说明:
创建好表 A, B, C 如下图所示:
第一次循环:
pa->data == pb->data && pb->data == pc->data
不满足,且
pa->data < pb->data
pb->data < pc->data
所以,pa, qa, pb 都向后移:
第二次循环:
pa->data == pb->data && pb->data == pc->data;
不满足,且:
pa->data < pb->data;
所以将 pa, qa 后移:
第三次循环:
满足:
pa->data == pb->data && pb->data == pc->data;
则,删除 pa 指向的结点,且 pb, pc 后移:
第四次循环:
满足:
pa->data == pb->data && pb->data == pc->data;
则,删除 pa 指向的结点,且 pb, pc 后移:
第五次循环:
满足:
pa->data == pb->data && pb->data == pc->data;
则,删除 pa 指向的结点,且 pb, pc 后移,注意:此时的 pa 指向 NULL!
此时,不满足 while 循环的条件,跳出循环!结束!
THE END!