教材《数据结构》第31页继续讨论如何将两个有序链表并为一个有序链表
假设头指针为La和Lb的单链表分别为线性表LA和LB的存储结构,现要归并La和Lb得到单链表Lc,之前已经在2.2笔记线性表合并中提到过合并(算法2.7(P26)),相同点都是要La和Lb是有序链表,然后判断pa->data<=pb->data时,则将pa所指结点链接到pc所指结点之后,否则将pb所指结点链接到pc所指结点之后。同时下面程序用到的算法2.12(P31)的时间复杂度和算法2.7相同。
两个算法(算法2.7和算法2.12)不同之处在于空间复杂度不同。下面的程序在归并两个链表为一个链表时,不需要另建立新表的结点空间,而只需将原来两个链表中结点之间的关系解除,重新按元素值非递减的关系将所有结点链接成一个链表。
下面的源代码涉及到了算法2.11(P30)和算法2.12(P31)。算法2.11逆序建立带表头结点的单链表,算法2.12是归并有序的La和Lb为新的有序单链表Lc。
//algo2-3.cpp实现算法2.11和算法2.12的程
#include<stdio.h>
#include<malloc.h>
typedef int ElemType;
struct LNode{
ElemType data;
LNode *next;
};
typedef LNode * LinkList;//定义LinkList为LNode型指针
void CreateList1(LinkList &L,int n){
//正位序(结点插在表尾)输入n个元素的值,建立带表头结点的单链线性表L
int i;
LinkList p,q;
L=(LinkList)malloc(sizeof(LNode));//生成头结点
L->next=NULL;//先建立一个带头结点的空单链表
q=L;//q指向空表的头结点(相当于尾结点)
printf("请输入%d个数据\n",n);
for(i=1;i<=n;i++)
{
p=(LinkList)malloc(sizeof(LNode));
scanf("%d",&p->data);//给新结点输入元素值
q->next=p;//将新结点插在表尾
q=q->next;//q指向尾结点,亦即p和q指向同一个结点
}
p->next=NULL;//最后一个结点的指针指针域为空
}
void CreateList(LinkList &L,int n){//算法2.11
//逆位序(结点插在表头)输入n个元素的值,建立带表头结点的单链线性表L
int i;
LinkList p;
L=(LinkList)malloc(sizeof(LNode));//生成头结点
L->next=NULL;//先建立一个带头结点的空单链表
printf("请输入%d个数据\n",n);
for(i=n;i>0;--i)
{
p=(LinkList)malloc(sizeof(LNode));//生成新结点
scanf("%d",&p->data);//给新结点输入元素值
p->next=L->next;//将新结点插在表头
L->next=p;//头结点指向新结点
}
}
void print(ElemType e){
printf("%d ",e);
}
void ListTraverse(LinkList L,void (*visit)(ElemType )){
//初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数visit()
LinkList p=L->next;
while(p)//p所指结点存在
{
visit(p->data);//对p所指结点调用函数visit()
p=p->next;//p指向下一个结点
}
printf("\n");
}
void MergeList(LinkList La,LinkList &Lb,LinkList &Lc){//算法2.12
//已知单链线性表La和Lb的元素按值非递减排列
//归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列(销毁Lb,Lc即新的La)
LinkList pa=La->next,pb=Lb->next,pc;//pa,pb分别指向La,Lb的首元结点(待比较结点)
Lc=pc=La;//用La的头结点作为Lc的头结点,pc指向La的头结点(Lc的尾结点)
while(pa&&pb){//La和Lb中的元素都未比较完
if(pa->data<=pb->data)//La的当前元素不大于Lb的当前元素
{
pc->next=pa;//将pa所指结点归并到Lc中
pc=pa;//pc指向表Lc的最后一个结点
pa=pa->next;//表La的下一个结点成为待比较结点
}else//Lb的当前元素小于La的当前元素
{
pc->next=pb;//将pb所指结点归并到Lc中
pc=pb;//pc指向表Lc的最后一个结点
pb=pb->next;//表Lb的下一个结点成为待比较结点
}
}
pc->next=pa?pa:pb;//插入剩余段
free(Lb);//释放Lb的头结点
Lb=NULL;//Lb不再指向任何结点
}
void main(){
int n=5;
LinkList La,Lb,Lc;
printf("按非递减排序");
CreateList1(La,n);//根据输入顺序,正无序建立线性表
printf("La=");
ListTraverse(La,print);//输出链表La的内容
printf("按非递增排序");
CreateList(Lb,n);//根据输入顺序,逆位序建立线性表
printf("Lb=");
ListTraverse(Lb,print);//输出链表Lb的内容
MergeList(La,Lb,Lc);//按非递减顺序归并La和Lb,得到新表Lc
printf("Lc=");
ListTraverse(Lc,print);//输出链表Lc的内容
}
结果图: