Problem9:
链表归并问题描述:已知有两个递增的正整数序列A和B,序列中元素个数未知,同一序列中不会有重复元素出现,有可能某个序列为空。现要求将序列B归并到序列A中,且归并后序列A的数据仍然按递增顺序排列。如果序列B中某些数据在序列A中也存在,则这些数据所在节点仍然留在序列B中,而不被归并到序列A中;否则这些数据所在节点将从序列B中删除,添加到序列A中。建立两个单链表A、B用于存储两个正整数序列,然后按照题目的要求,将链表B中的元素归并到链表A中。在归并的过程中,不要释放B中的节点空间、然后建立新节点,而要改变指针的指向,使元素从B中删除并添加到A中。正整数序列按照递增顺序输入,用-1作为结束标志,注意-1不算这个正整数序列中的元素(不要统计-1)。在程序结束前要释放链表A、B中的所有节点。输入与输出要求:依次输入两个递增的正整数序列A和B,序列元素的个数未知,但以输入-1结束,每个正整数序列占一行。输出处理后的链表A中的元素,占一行;然后是处理后的链表B中的元素,占一行。每行的元素之间有一个空格,注意最后一个元素后只有换行符,如果某个链表为空,则输出“ThereisnoiteminXlist.”。
程序运行效果:
Sample1:
Please input the elements of listA:1 3 4 5 6 7 -1↙
Please input the elements of listB:2 3 6 8 9 10 11 -1↙
The new listA:1 2 3 4 5 6 7 8 9 10 11
The new listB:3 6
Sample2:
Please input the elements of listA:-1↙
Please input the elements of listB:-1↙
There is no item in Alist.
There is no item in Blist.
#include<stdio.h>
#include<stdlib.h>
typedef struct List{
int number;
struct List* next;
}list;
typedef list* listPtr;
listPtr print(void); //创建链表并输入数据
listPtr sort(listPtr); //链表排序
void main()
{
listPtr A,B;
//输入A、B
printf("listA\n");
A=print();
printf("listB\n");
B=print();
if(A!=NULL&&B!=NULL) /*在A、B都不为空的一般情况下*/
{
//将A、B合为一个链表
listPtr lastA;
for(lastA=A;lastA->next!=NULL;lastA=lastA->next);
lastA->next=B;
listPtr head=A;
//对新的链表进行排序
head=sort(head);
/*对新的链表进行如下处理:将新链表记为A链表遍历链表,若有
某两节点中储存的数据相同,则第一个节点仍在A链表中,将第二
个节点移动到B链表中*/
A=head;
B=NULL;
listPtr ba=head,a=head->next,b=NULL; /*ba为a节点的前一节点
a节点为A链表中的临时
节点,b节点为将要存到
B链表中的临时节点*/
while(a!=NULL)
{
if(ba->number==a->number) /*找到A链表中储存数据
相同的两节点*/
{
ba->next=a->next;
if(b==NULL) /*此时B链表中没有节点*/
{
ba->next=a->next;
a->next=NULL;
b=a;
B=b;
a=ba->next;
}
else /*B链表中已有节点*/
{
ba->next=a->next;
a->next=NULL;
b->next=a;
b=a;
a=ba->next;
}
}
else /*循环*/
{
ba=a;
a=a->next;
}
}
//输出A、B链表并释放
printf("The new list A:");
for(a=A;A!=NULL;A=A->next)
printf("%d ",A->number);
for(b=a->next;b!=NULL;a=b,b=a->next)
free(a);
printf("\n");
if(B==NULL)
printf("There is no item in B list.");
else
{
printf("The new list B:");
for(a=B;B!=NULL;B=B->next)
printf("%d ",B->number);
}
for(b=a->next;b!=NULL;a=b,b=a->next)
free(a);
}
else
{
listPtr a,b; /*用于释放链表*/
if(A!=NULL) /*A不为空,则B必为空*/
{
printf("The new list A:");
for(a=A;A!=NULL;A=A->next)
printf("%d ",A->number);
for(b=a->next;b!=NULL;a=b,b=a->next)
free(a);
printf("\n");
printf("There is no item in B list.");
}
else if(B!=NULL) /*A为空,B不为空
则B中数据均储存
到A中,B变为空*/
{
A=B;
printf("The new list A:");
for(a=A;A!=NULL;A=A->next)
printf("%d ",A->number);
for(b=a->next;b!=NULL;a=b,b=a->next)
free(a);
printf("\n");
printf("There is no item in B list.");
}
else /*A、B均为空*/
{
printf("There is no item in A list.\n");
printf("There is no item in B list.");
}
}
return 0;
}
//创建链表输入数据
listPtr print(void)
{
listPtr head=NULL,last=NULL,current=NULL;
int num;
scanf("%d",&num);
while(num!=-1)
{
current=(listPtr)malloc(sizeof(list));
current->number=num;
current->next=NULL;
if(head==NULL)
{
head=current;
last=current;
}
else
{
last->next=current;
last=current;
}
scanf("%d",&num);
}
return head;
}
//链表排序
listPtr sort(listPtr head)
{
/*链表排序*/
/*排序思路:将链表中的某一结点p,与该节点之前的节点q逐一比较大小,
假设此时q节点中的number大于p节点中的number,则将p节点插入到q节点
之前*/
/*插入方式为:1、令p节点的前一节点bp(before p)中指针指向p节点的
后一节点; 2、令p节点指针指向q节点; 3、令q节点的前一节点bq
中的指针指向p节点。*/
/*如此操作之后可知,循环之初的p节点为bp->next,即链表第三节点,
q节点为bq->next,即链表第二节点, 故而比较大小是从第三节点开始每
一节点和第二节点进行比较,而忽略了头节点,即该组数据的第一个数。
因此:必须先找到链表中最小的节点并将该节点作为头节点,再进行上述操作*/
/*找到链表中的最小节点并作为头节点*/
listPtr min,current;
min=(listPtr)malloc(sizeof(list)); //创建临时内存空间存储最小节点
min->number=head->number;
min->next=NULL;
for(current=head;current!=NULL;current=current->next)
{
if(min->number>current->number)
{
min->number=current->number;
}
}
min->next=head;
head=min; //头节点设为链表中的最小节点
/*排序*/
listPtr bp=head->next,p=bp->next,bq=head,q=bq->next,newp;
while(p)
{
for(bq=head,q=bq->next;q!=p;bq=q,q=q->next)
{
if(q->number>=p->number) /*判断q中number大于p*/
{
newp=p; /*复制p节点为newp*/
bp->next=p->next; /*bp指向p的下一节点*/
newp->next=q; /*newp指向q*/
bq->next=newp; /*bq指向newp*/
p=p->next; /*p更正为p的下一节点,以便循环*/
break;
}
}
if(q==p) /*此为p节点之前的所有节点均小于p*/
{
bp=p; /*bp更正为bp的下一节点*/
p=p->next; /*p更正为p的下一节点*/
}
}
p=head;
head=head->next;
free(p); /*释放临时储存空间*/
return head;
}