两个非递增的有序顺序表的合并
一、问题引入:
已知两个带头结点的非递增有序的单链表A和B,设计算法将两个单链表合并成一个非递增有序的单链表C.要求单链表C仍使用原来两个链表的存储空间
二、分析
两个链表都是有序的,我们直接将A的头节点作为结果集链表的头节点,用pa和pb作为A和B的工作指针,循环比较pa和pb的数据域,将较大值接入结果集链表的尾部就行,如果俩个链表的长度不一致,最后会有一个链表剩余,将剩余的所有结点直接接在结果集链表的尾部就ok。
三、算法实现:
代码语言:javascript复制typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
代码语言:javascript复制//两个非递增的链表合并,要求合并后的链表元素也是非递增顺序,且不使用额外的空间。
LinkList merge_list(LinkList A,LinkList B)
{
LNode *pa=A->next;
LNode *pb=B->next;
LNode *r;
LNode *r1=A;//结果接链表的工作指针
A->next=NULL;//A作为结果集链表的头指针
while(pa&&pb)
{
if(pa->data>pb->data)
{
r=pa->next;
pa->next=NULL;
r1->next=pa;//接在结果集链表的尾部
r1=pa; //让r1始终指向结果集链表的表尾
pa=r; //恢复pa为当前带比较结点
}
else
{
r=pb->next;
pb->next=NULL;
r1->next=pb;
r1=pb;
pb=r;
}
}//end while
//通常情况会有一个链表非空
while(pa)
{
r=pa->next;
pa->next=NULL;
r1->next=pa;//接在结果集链表的尾部
r1=pa; //让r1始终指向结果集链表的表尾
pa=r; //回复pa为当前带比较结点
}
while(pb)
{
r=pb->next;
pb->next=NULL;
r1->next=pb;
r1=pb;
pb=r;
}
free(B);
return A;
}
三、完整代码实现:
link.h:
代码语言:javascript复制typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}LNode,*LinkList;
//头插法
LinkList List_HeadInsert(LinkList &L) //这是c 的写法,C语言用的是双重指针
{
LNode *s;
int x;
L=(LinkList)malloc(sizeof(LNode));//创建头结点
L->next=NULL;
scanf("%d",&x); //输入结点的值
while(x!=9999) //下面这段一直插入结点,知道输入9999结束
{
s=(LNode*)malloc(sizeof(LNode));//创建头结点
s->data=x;
s->next=L->next;
L->next=s; //将新结点插入链表中
scanf("%d",&x);
}
return L;
}
//尾插法
LinkList List_TailInsert(LinkList &L)
{
int x;
L=(LinkList)malloc(sizeof(LNode));
LNode *s,*r=L; //r为表尾指针
scanf("%d",&x); //输入结点的值
while(x!=9999)
{
s=(LNode *)malloc(sizeof(LNode));
s->data=x;
r->next=s;
r=s;
scanf("%d",&x);
}
r->next=NULL; //尾结点指针置空
return L;
}
//按序号查找结点值
LNode *GetElem(LinkList L,int i)
{
int j=1; //计数,初始值为1
LNode *p=L->next; // 头结点赋值给指针p
if(i==0)
return L; //若i==0,返回头结点
if(i<1)
return NULL;
while(p&&j<i) //从第一个结点开始查找,查找第i个结点
{
p=p->next;
j ;
}
return p; //返回第i个结点的指针,若i大于表厂则返回NULL
}
//按值查找表结点
LNode *LocateElem(LinkList L,ElemType e)
{
LNode *p=L->next;
while(p!=NULL&&p->data!=e)
{
p=p->next;
}
return p;
}
int print(LinkList L)
{
if(L->next==NULL)
{
printf("链表为空!");
return 0;
}
LNode *p=L->next;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
printf("n");
return 1;
}
//插入结点操作
int Insert(LinkList L,int i,ElemType x)
{
LNode *p,*s;
s=(LNode *)malloc(sizeof(LNode));
s->next=NULL;
s->data=x;
p=GetElem(L,i-1); //找到插入位置的前驱结点
s->next=p->next;
p->next=s;
return 1;
}
//删除节点操作
int Delete(LinkList L,int i,ElemType *x)
{
LNode *p,*q;
p=GetElem(L,i-1); //找到删除位置的前驱结点
q=p->next; //q指向被删除的结点
p->next=q->next;
*x=q->data;
free(q);
return 1;
}
//求表长操作
int ListLength(LinkList L)
{
LNode *p=L->next;
int count=0;
while(p!=NULL)
{
count ;
p=p->next;
}
return count;
}
//链表逆序输出(但这个会把头结点的数据域也输出)
//也可以堆栈来实现,这样就不会把头结点的数据域的值输出
void contrary(LinkList L)
{
if(L->next!=NULL)
{
contrary(L->next);
}
if(L!=NULL)
{
printf("%d ",L->data);
}
}
//链表排序算法
void linksort(LinkList &L)
{
//本算法实现将单链表L的结点重排,使其递增有序
LNode *p=L->next,*pre;
LNode *r=p->next; //r保持*p后继结点指针,以保证不断链
p->next=NULL; //构造只含一个数据结点的有序表
p=r;
while(p!=NULL)
{
r=p->next; //保存*p的后继节点指针
pre=L;
while(pre->next!=NULL&&pre->next->data<p->data){
pre=pre->next; //在有序表中查找插入*p的前驱节点*pre
}
p->next=pre->next; //将*p插入到*pre之后
pre->next=p;
p=r; //扫描原来单链表中剩下的结点
}
}
//按照递增次序输出链表所有元素并是放过结点的 存储空间(有bug)
void Min_Delete(LinkList &head)
{
LNode *p,*pre,*u;
//head是带头节点的单链表的头指针,本算法按递增顺序输出单链表中的数据元素
while(head->next!=NULL){
pre=head;
p=pre->next;
while(p->next!=NULL){
if(p->next->data<pre->next->data)
{
pre=p;
}
p=p->next;
}
printf("%d ",pre->next->data);
u=pre->next;
pre->next=u->next;
free(u);
}
free(head);
}
//删除单链表中值相同的元素
void Del_Same(LinkList &L)
{
//L是递增有序的单链表,本算法删除表中数值相同的元素
LNode *p=L->next,*q; //p为工作扫描指针
if(p==NULL)
{
return;
}
while(p->next!=NULL){
q=p->next; //q指向*p的后继结点
if(p->data==q->data){ //找到重复值得结点
p->next=q->next;
free(q); //释放相同元素值的结点
}
else
p=p->next;
}
}
//本算法产生单链表A和B的公共元素的单链表C
void Get_Common(LinkList A,LinkList B)
{
LNode *p=A->next,*q=B->next,*r,*s;
LinkList C=(LinkList)malloc(sizeof(LNode));//建立表C
r=C; //r始终指向C的尾结点
while(p!=NULL&&q!=NULL){ //循环跳出条件
if(p->data<q->data){ //若A的当前元素小,后移指针
p=p->next;
}
else if(p->data>q->data) //若B的当前元素小,后移指针
{
q=q->next;
}
else //找到公共元素结点
{
s=(LNode *)malloc(sizeof(LNode));
s->data=p->data;
r->next=s; //将*s链接到C上(尾插法)
r=s;
p=p->next; //表A和B继续向后扫描
q=q->next;
}
}
r->next=NULL; //置C尾结点指针为空
printf("链表C的所有元素如下:n");
print(C);
}
//求连个递增链表的交集,结果存放在A链表中
LinkList Union(LinkList &la,LinkList &lb)
{
LNode* pa=la->next;
LNode* pb=lb->next;
LNode *pc=la;
while(pa&&pb){
if(pa->data==pb->data){//交集并入结果表中
pc->next=pa; //A中结点链接到结果表
pc=pa;
pa=pa->next;
LNode *u=pb; //B中结点释放
pb=pb->next;
free(u);
}
else if(pa->data<pb->data){
LNode *u=pa;
pa=pa->next;
free(u);
}
else{
LNode* u=pb;
pb=pb->next;
free(u);
}
}//while循环结束
while(pa) //B已经遍历完,A有剩余
{//释放A中剩余结点
LNode *u=pa;
pa=pa->next;
free(u);
}
while(pb)//A已经遍历完,B有剩余
{//释放B中剩余节点
LNode *u=pb;
pb=pb->next;
free(u);
}
pc->next=NULL; //置结果链表的尾指针为空
free(lb);
return la;
}
//判断b链表是否是A的连续子链表
int Pattern(LinkList A,LinkList B)
{//A和B都是数据域为整数的单链表,本算法判断B是否是A的子序列
LNode *p=A->next;
LNode *pre=p;
LNode *q=B->next;
while(p&&q)
{
if(p->data==q->data)
{
p=p->next;
q=q->next;
}
else
{
pre=pre->next;
p=pre; //A链表新的开始比较结点
q=B->next; //q从B链表的第一个数据结点开始
}
}
if(q==NULL)//B已经比较结束
return 1; //B是A的自序列
else
return 0; //B不是A的自序列
}
//王道单链表第25题将L(a1,a2,a3,a4...an)----->L'(a1,an,a2,an-1.....)
void change_list(LinkList &head)
{
LNode *p,*q,*r,*s;
p=q=head;
while(q->next!=NULL)
{
p=p->next; //p走一步
q=q->next;
if(q->next!=NULL)//q走两步
q=q->next;
}
q=p->next; //p所指结点为中间结点,q为后半段链表的首节点
p->next=NULL;
while(q!=NULL)
{
r=q->next;
q->next=p->next;
p->next=q;
q=r;
}
s=head->next;//s指向前半段的第一个数据结点,即插入点
q=p->next; //q指向后半段的第一个数据结点
p->next=NULL;
while(q!=NULL)
{
r=q->next;
q->next=s->next; //将q所指结点插入到s所指结点之后
s->next=q;
s=q->next; //s指向前半段的下一个插入点
q=r;
}
}
//两个非递增的链表合并,要求合并后的链表元素也是非递增顺序,且不使用额外的空间。
LinkList merge_list(LinkList A,LinkList B)
{
LNode *pa=A->next;
LNode *pb=B->next;
LNode *r;
LNode *r1=A;//结果接链表的工作指针
A->next=NULL;//A作为结果集链表的头指针
while(pa&&pb)
{
if(pa->data>pb->data)
{
r=pa->next;
pa->next=NULL;
r1->next=pa;//接在结果集链表的尾部
r1=pa; //让r1始终指向结果集链表的表尾
pa=r; //恢复pa为当前带比较结点
}
else
{
r=pb->next;
pb->next=NULL;
r1->next=pb;
r1=pb;
pb=r;
}
}//end while
//通常情况会有一个链表非空
while(pa)
{
r=pa->next;
pa->next=NULL;
r1->next=pa;//接在结果集链表的尾部
r1=pa; //让r1始终指向结果集链表的表尾
pa=r; //回复pa为当前带比较结点
}
while(pb)
{
r=pb->next;
pb->next=NULL;
r1->next=pb;
r1=pb;
pb=r;
}
free(B);
return A;
}
test.cpp:
代码语言:javascript复制#include<stdio.h>
#include<malloc.h>
typedef int ElemType;
#include"link.h"
int main()
{
int number;
// int number,x;
LinkList mylist,mylist1,mylist2;
// List_HeadInsert(mylist);
printf("请输入第一个链表的元素:n");
List_TailInsert(mylist);
printf("请输入第二个链表的元素:n");
List_TailInsert(mylist1);
print(mylist);
print(mylist1);
mylist2=merge_list(mylist,mylist1);
print(mylist2);
return 0;
}