首页 > 其他分享 >两个非递增的有序链表的合并

两个非递增的有序链表的合并

时间:2023-02-13 11:35:55浏览次数:41  
标签:pb 结点 LNode 递增 next 链表 pa 有序

两个非递增的有序顺序表的合并

一、问题引入:

已知两个带头结点的非递增有序的单链表A和B,设计算法将两个单链表合并成一个非递增有序的单链表C.要求单链表C仍使用原来两个链表的存储空间

二、分析

两个链表都是有序的,我们直接将A的头节点作为结果集链表的头节点,用pa和pb作为A和B的工作指针,循环比较pa和pb的数据域,将较大值接入结果集链表的尾部就行,如果俩个链表的长度不一致,最后会有一个链表剩余,将剩余的所有结点直接接在结果集链表的尾部就ok。

三、算法实现:

typedef struct LNode{
 ElemType data;           //数据域
 struct LNode *next;      //指针域
}LNode,*LinkList;
//两个非递增的链表合并,要求合并后的链表元素也是非递增顺序,且不使用额外的空间。
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:

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:

#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;
}

标签:pb,结点,LNode,递增,next,链表,pa,有序
From: https://blog.51cto.com/u_15961549/6053828

相关文章

  • 合并两个有序
    给你两个按非递减顺序排列的整数数组nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你合并nums2到nums1中,使合并后的数组同样按......
  • 蓝桥杯链表总结(3)
    力扣链表相关题目反转链表题目:给你单链表的头节点head,请你反转链表,并返回反转后的链表。示例1:输入:head=[1,2,3,4,5]输出:[5,4,3,2,1]示例2:输入:head=[1,2]......
  • 【CTO变形记】有序定无序—为什么越努力,越无力
     前言:我们用自己构建的认知结构来理解和映射这个世界,通过外界的反馈来调整现有的认知。但面对的现实越来越复杂,以及面对更多的未知且陌生的情况时,我们常常试图去“修......
  • java: 小王子单链表 ------ ( LinkedList )
    java.util包中的LinkedList<E>泛型类创建的对象以链表结构存储数据,习惯上称LinkedList类创建的对象为链表对象。LinkedList<String>myList=newLinkedList<String>(......
  • LeetCode算法题二——合并两个有序链表
    题目给你一个非空整数数组nums,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问......
  • 【DFS】LeetCode 108. 将有序数组转换为二叉搜索树
    题目链接108.将有序数组转换为二叉搜索树思路类似于二分搜索,定位到数组中间mid,然后左边的子数组构成左子树,右边的子数组构成右子树,mid处的数字构成根结点。递归构建......
  • 算法刷题-插入区间、杨辉三角、移除链表元素
    插入区间给你一个无重叠的,按照区间起始端点排序的区间列表。在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。示例1:输入......
  • 1.顺序表递增有序,插入元素x,使之仍递增有序
    intfind(SqlistL,intx)//找到x应该插入的位置{for(inti=0;i<L.length;++i){if(x<L.data[i])break;}returni;}void......
  • 环形链表I、II(含代码以及证明)
    环形链表解题思路定义两个指针,一个快指针,一个慢指针,快指针每次移动两个节点,慢指针每次移动一个节点。从头节点开始,让快慢指针同时移动,如果链表中有环,那么快慢指针一定......
  • LeetCode-88. 合并两个有序数组(java)
    一、前言:......