已知单链表 A, B 和 C 均为递增有序排列,现要求对 A 表作如下操作:删去那些既在 B 表中出现又在 C 表中出现的元素。试对单链表编写实现上述操作的算法。

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!

 

  • 18
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值