有两个按元素递增有序排列的链表L1和L2,编写一个程序将L1表和L2表归并成一个按元素递增有序的链表L3。要求:
1链表中允许有相同的元素,只要L1,L2,L3单调不减即可;
2要利用原表空间(即L1表和L2表)的节点空间构造表L3;
分析:
考虑将表2的元素一个个插入到表1的相应位置上构成新表;
首先,创建两个链表(很简单,这里就不细讲了):
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
归并后要将结果打印出来,当然少不了打印函数了:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
设计归并函数:combine()
现在考虑:
处理两个链表的节点的关系,那么表1和表2每个都至少都应该有一个指针:这里分别为p和q1:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
combine(node*l1,node*l2);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
combine(node*l1,node*l2)
{
node*p,*q1,*l3,*q2;
p=l1;
q1=l2;
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
将表2从头遍历到尾,每访问一个元素i,就在表1中从头开始找,找到的第一个比i大的元素,就把i插入到它的前面;
为了完成插入,指向表2的元素的指针q1后面要紧跟一个指针q2,因为q1指向的节点接入表1后从q1指向的节点开始就不能遍历表2了,有了q2才能继续向下遍历表2;
遍历表2,在表1中搜索,一共需要两个循环。由前面的分析知这两个循环应该是嵌套的,由于在表1的搜索不一定是全部走完的,一定的情况下要退出,所以搜索表1的循环嵌套在里层:每循环一次相应的指针顺着链表下移一位,(注意内层循环每次结束后p指针要复位!)
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
combine(node*l1,node*l2);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
combine(node*l1,node*l2)
{
node*p,*q1,*q2;
p=l1;
q1=l2;
q2=q1->next;
while(q2!=NULL)
{
while(p!=NULL)
{
p=p->next;
}
p=l1; //注意,p别忘复位!
q1=q2;
q2=q2->next;
}
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
要实现插入,q1指向的元素只能插在p指针指向的元素的下一个,所以在搜索表1的时候加入这么一个退出条件(找到比q1所指元素还大的元素):符合条件的时候退出里层循环并且将q1指向的元素插入p指向的元素的下一个元素:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
combine(node*l1,node*l2);
void insert(node*q1,node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
combine(node*l1,node*l2)
{
node*p,*q1,*q2;
p=l1;
q1=l2;
q2=q1->next;
while(q2!=NULL)
{
while(p!=NULL)
{ if(p->next->item>=q1->item)
{
insert(q1,p);
break;
}
p=p->next;
}
p=l1;
q1=q2;
q2=q2->next;
}
}
void insert(node*q1,node*p)
{
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
设计插入函数insert():
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
combine(node*l1,node*l2);
void insert(node*q1,node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
node* combine(node*l1,node*l2)
{
node*p,*q1,*q2;
p=l1;
q1=l2;
q2=q1->next;
while(q2!=NULL)
{
while(p!=NULL)
{ if((p->next->item>=q1->item)||(p->next==NULL))
{
insert(q1,p);
break;
}
p=p->next;
}
p=l1;
q1=q2;
q2=q2->next;
}
return l3;
}
void insert(node*q1,node*p)
{
node*turn;
turn=p->next;
p->next=q1;
q1->next=turn;
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
有一种特殊情况:如果表1中所有元素都比q1指向的元素小,那么这个元素就会被插在表1的最后,还好这可以在同一个inser函数里面实现,加一个判断分支即可;
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
node* combine(node*l1,node*l2);
void insert(node*q1,node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
node* combine(node*l1,node*l2)
{
node*p,*q1,*l3,*q2;
p=l1;
q1=l2;
q2=q1->next;
l3=l1;
if(p->item>=q1->item)
{
l3=q1;
q1->next=p;
q1=q2;
q2=q2->next;
}
while(q2!=NULL)
{
while(p!=NULL)
{ if((p->next->item>=q1->item)||(p->next==NULL))
{
insert(q1,p);
break;
}
p=p->next;
}
p=l1;
q1=q2;
q2=q2->next;
}
return l3;
}
void insert(node*q1,node*p)
{
node*turn;
if(p->next!=NULL)
{
turn=p->next;
p->next=q1;
q1->next=turn;
}
else
{
p->next=q1;
q1->next=NULL;
}
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
还有一种特殊情况:如果表1第一个元素就比q1指向的元素大,那么就要插在表1的第一个位置,这样表1的表头就变了,所以最后归并后链表的头结点地址不一定是原来表1的头结点地址;
由题意,这种特殊情况只有在q1指向表2的第一个元素时可能出现,所以他可以单独抽出来排除而不必置于循环中,若存在这种情况,那么表头就变了,所以combine函数应该返回归并后链表的头结点:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
node* combine(node*l1,node*l2);
void insert(node*q1,node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
node* combine(node*l1,node*l2)
{
node*p,*q1,*l3,*q2;
p=l1;
q1=l2;
q2=q1->next;
l3=l1;
if(p->item>=q1->item)
{
l3=q1;
q1->next=p;
q1=q2;
q2=q2->next;
}
while(q2!=NULL)
{
while(p!=NULL)
{ if((p->next->item>=q1->item)||(p->next==NULL))
{
insert(q1,p);
break;
}
p=p->next;
}
p=l1;
q1=q2;
q2=q2->next;
}
return l3;
}
void insert(node*q1,node*p)
{
node*turn;
if(p->next!=NULL)
{
turn=p->next;
p->next=q1;
q1->next=turn;
}
else
{
p->next=q1;
q1->next=NULL;
}
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
漏了什么?没错,如果以q2指向空节点为循环结束条件,那么表2的最后一个节点就不会插入表1了。这里只要在最后另外单独加一个while循环即可
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
node* combine(node*l1,node*l2);
void insert(node*q1,node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
node* combine(node*l1,node*l2)
{
node*p,*q1,*l3,*q2;
p=l1;
q1=l2;
q2=q1->next;
l3=l1;
if(p->item>=q1->item)
{
l3=q1;
q1->next=p;
q1=q2;
q2=q2->next;
}
while(q2!=NULL)
{
while(p!=NULL)
{ if((p->next==NULL)||(p->next->item>=q1->item))
{
insert(q1,p);
break;
}
p=p->next;
}
p=l1;
q1=q2;
q2=q2->next;
}
while(p!=NULL)
{
if((p->next==NULL)||(p->next->item>=q1->item))
{
insert(q1,p);
break;
}
p=p->next;
}
return l3;
}
void insert(node*q1,node*p)
{
node*turn;
if(p->next!=NULL)
{
turn=p->next;
p->next=q1;
q1->next=turn;
}
else
{
p->next=q1;
q1->next=NULL;
}
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}
代码清单:
#include<stdio.h>
#include<stdlib.h>
typedef struct node
{
int item;
node*next;
}node;
void create(node*p);
node* combine(node*l1,node*l2);
void insert(node*q1,node*p);
void print(node*p);
main()
{
int m;
node*l1,*l2,*l3;
l1=(node*)malloc(sizeof(node));
printf("Please enter the first number of list1:/n");
scanf("%d",&m);
l1->item=m;
create(l1);
l2=(node*)malloc(sizeof(node));
printf("Please enter the first number of list2:/n");
scanf("%d",&m);
l2->item=m;
create(l2);
l3=combine(l1,l2);
print(l3);
}
void create(node*p)
{
int i;
printf("Please enter a number:/n");
scanf("%d",&i);
if(i==-1)
{
p->next=NULL;
return;}
else
{
p->next=(node*)malloc(sizeof(node));
p->next->item=i;
create(p->next);
}
}
node* combine(node*l1,node*l2)
{
node*p,*q1,*l3,*q2;
p=l1;
q1=l2;
q2=q1->next;
l3=l1;
if(p->item>=q1->item)
{
l3=q1;
q1->next=p;
q1=q2;
q2=q2->next;
}
while(q2!=NULL)
{
while(p!=NULL)
{ if((p->next==NULL)||(p->next->item>=q1->item))
{
insert(q1,p);
break;
}
p=p->next;
}
p=l1;
q1=q2;
q2=q2->next;
}
while(p!=NULL)
{
if((p->next==NULL)||(p->next->item>=q1->item))
{
insert(q1,p);
break;
}
p=p->next;
}
return l3;
}
void insert(node*q1,node*p)
{
node*turn;
if(p->next!=NULL)
{
turn=p->next;
p->next=q1;
q1->next=turn;
}
else
{
p->next=q1;
q1->next=NULL;
}
}
void print(node*p)
{
printf("%d/n",p->item);
if(p->next==NULL)
{
return;
}
print(p->next);
}