算法:其实这和直接删除a链表中的某个节点类似,只是现在不是在删除一个节点,而是要与b链表先进行比较后再进行删除。首先先选取a中的第一个节点,从b中第一个开始找,找不到的话b就继续后移,b移到结尾还是未找到就说明b中任何一个没有与a中第一个节点相同,则a向后移动,以此类推。当有找到相同的节点时,情况1.此时a链表指向头结点,则只需要让头结点指向下一结点。情况2.不是头结点时只需要让a的前一个节点(pa2)的next指向pa1的next即可。情况3.如果是表尾,这个情况要考虑仔细了,假设现在b中找到了一个元素是与a中的最后一个节点相同,这时a中的指针情况应该是pa2指向倒数第二个节点(它始终是pa1的前驱,记录前一个走过的节点),而pa1指向末尾节点,则按照情况2的思路,有如下操作:pa2->next=pa1->next;而此时pa1->next为NULL(它是末尾么),所以还是满足情况2的,因此2,3情况可以合并,但是要注意循环的条件是while(pa1!=null),即pa1可以指向最后一个节点,但pa2不能指向最后一个节点,因为这时pa2的后继pa1就指向了下一个空节点了。
#include <stdio.h>
#include <string.h>
#define LA 5
#define LB 4
struct student
{
int num;
char name[10];
struct student *next;
}a[LA],b[LB];
void main()
{
struct student a[LA]={{101,"zhang"},{102,"li"},{103,"wang"},{104,"niu"},{105,"liu"}};
struct student b[LB]={{103,"zhu"},{105,"huang"},{106,"zhao"},{107,"qian"}};
struct student *heada,*headb,*pa1,*pa2,*pb1;
int i;
heada=a;//指向a链表
headb=b;//指向b链表
//对链表a赋地址并且输出
printf("a链表:\n");
for (pa1=heada,i=1;i<=LA;i++)
{
if(i<LA)
pa1->next=a+i;
else
pa1->next=NULL;
printf("%4d%8s\n",pa1->num,pa1->name);
if(i<LA)
pa1=pa1->next;
}
//对链表b赋地址并且输出
printf("b链表:\n");
for (pb1=headb,i=1;i<=LB;i++)
{
if(i==LB)
pb1->next=NULL;
else
pb1->next=b+i;
printf("%4d%8s\n",pb1->num,pb1->name);
if(i<LB)
pb1=pb1->next;
}
//从a中找出与b相同的节点并且删除
pa1=heada;//初始化指针
while (pa1!=NULL)//只要链表a没有到结尾就执行
{ pb1=headb;
while((pa1->num != pb1->num) && (pb1->next!=NULL))//没有找到相等的值且b表没有到结尾
{pb1=pb1->next;}//b表向后移动
if (pa1->num==pb1->num)//找到了
{
if(pa1==heada)
heada=pa1->next;//头结点直接指向下一结点
else
{
pa2->next=pa1->next;//乍一看觉得pa2没有指向,但能进入这个else说明绝对有一次没有找到过,
pa1=pa1->next; //即pa1向后移动过,所以pa2是有所指的
}
}
else
{pa2=pa1;
pa1=pa1->next;
}
}
//输出新表
printf("现在a链表如下:\n");
pa1=heada;
while(pa1!=NULL)
{
printf("%4d%8s\n",pa1->num,pa1->name);
pa1=pa1->next;
}
}