算法题:合并两个有序的链表

说明:本文仅供学习交流,转载请标明出处,欢迎转载!

             题目:已知有两个有序的单链表,其头指针分别为head1和head2,实现将这两个链表合并的函数:

          Node* ListMerge(Node *head1,Node *head2)

       这个算法很像我们排序算法中的归并排序,只能说“很像”,因为思想是一样的,但是这个与归并排序还是有区别的,区别如下:

       1.归并排序是针对有序数组,而这里是有序链表;

       2.归并排序排序的时间复杂度为o(nlogn),而这里的时间复杂度最坏情况下为O(m+n),最好的情况下为O(min{m,n})。

       3.归并排序需要重新申请空间,而这里无需再重新申请空间,只需改变链表结点的指针指向。

       而这里算法的思想跟归并排序是一样的,都是对两个待归并的线性表分别设置1个指针,比较这两个当前指针的大小,将小的结点加入到合并后的线性表中,并向后移动当前指针。若两个线性表中,至少有一个表扫描完,走将对应的另一个表之间整体添加到合并后的线性表中。在这里:链表和数组的区别在于,链表只需要改变当前合并序列尾指针的位置,而数组则要将剩下的值依次复制到归并表的尾部

        算法的递归实现如下:

Node *ListMerge1(Node *head1,Node *head2)//采用递归的方法实现
{
	if(head1==NULL)
		return head2;
	if(head2==NULL)
		return head1;
	Node *head=NULL;
	if(head1->value < head2->value)
	{
		head=head1;
		head->next=ListMerge1(head1->next,head2);
	}
	else
	{
		head=head2;
		head->next=ListMerge1(head1,head2->next);
	}
	return head;
}

         算法的非递归实现如下:

Node *ListMerge(Node *head1,Node *head2)
{
	if(!head1) return head2;
	if(!head2) return head1;
	Node *head=NULL;//合并后的头指针
	Node *p1=head1;//p1用于扫描链表1
	Node *p2=head2;//p2用于扫描链表2
	if(head1->value<head2->value)
	{
		head=head1;
		p1=head1->next;
	}
	else
	{
		head=head2;
		p2=head2->next;
	}
	Node *p=head;//p永远指向最新合并的结点
	while(p1 && p2)//如果循环停止,则p1或p2至少有一个为NULL
	{
		if(p1->value<p2->value)
		{
			p->next=p1;
			p1=p1->next;
		}
		else
		{
			p->next=p2;
			p2=p2->next;
		}
		p=p->next;
	}
	if(p1)//如果链1还没走完
	{
		p->next=p1;
	}
	else if(p2)//如果链2还没走完
	{
		p->next=p2;
	}
	return head;
}

          整个测试代码如下:

#include<iostream>
using namespace std;
struct Node
{
	int value;
	Node* next;
	Node(int v):value(v){}
};
/*创建一个链表,1->2->3->4->5->6->7*/
Node* CreateList1()//创建一个有序的单链表1
{
   Node *head;
   Node *n1=new Node(1);
   Node *n3=new Node(3);
   Node *n5=new Node(5);
   Node *n7=new Node(7);
   Node *n9=new Node(9);
   head=n1;
   n1->next=n3;
   n3->next=n5;
   n5->next=n7;
   n7->next=n9;
   n9->next=NULL;
   return head;
}
Node* CreateList2()//创建一个有序的单链表2
{
   Node *head;
   Node *n2=new Node(2);
   Node *n4=new Node(4);
   Node *n6=new Node(6);
   Node *n8=new Node(8);
   head=n2;
   n2->next=n4;
   n4->next=n6;
   n6->next=n8;
   n8->next=NULL;
   return head;
}
void FreeList(Node *head)//将链表空间释放
{
	if(head==NULL)
	{
		return ;
	}
	else
	{
		Node *temp=head->next;
		delete head;
		head=temp;
		FreeList(head);
	}
}

void VisitList(Node *head)//遍历链表中的元素,用递归的方法遍历
{
	if(head)
	{
		cout<<head->value<<"->";
		VisitList(head->next);
	}
	else
	{
		cout<<"null"<<endl;
	}
}
Node *ListMerge(Node *head1,Node *head2)
{
	if(!head1) return head2;
	if(!head2) return head1;
	Node *head=NULL;//合并后的头指针
	Node *p1=head1;//p1用于扫描链表1
	Node *p2=head2;//p2用于扫描链表2
	if(head1->value<head2->value)
	{
		head=head1;
		p1=head1->next;
	}
	else
	{
		head=head2;
		p2=head2->next;
	}
	Node *p=head;//p永远指向最新合并的结点
	while(p1 && p2)//如果循环停止,则p1或p2至少有一个为NULL
	{
		if(p1->value<p2->value)
		{
			p->next=p1;
			p1=p1->next;
		}
		else
		{
			p->next=p2;
			p2=p2->next;
		}
		p=p->next;
	}
	if(p1)//如果链1还没走完
	{
		p->next=p1;
	}
	else if(p2)//如果链2还没走完
	{
		p->next=p2;
	}
	return head;
}

Node *ListMerge1(Node *head1,Node *head2)//采用递归的方法实现
{
	if(head1==NULL)
		return head2;
	if(head2==NULL)
		return head1;
	Node *head=NULL;
	if(head1->value < head2->value)
	{
		head=head1;
		head->next=ListMerge1(head1->next,head2);
	}
	else
	{
		head=head2;
		head->next=ListMerge1(head1,head2->next);
	}
	return head;
}
int main()
{
	Node *head1=CreateList1();
	Node *head2=CreateList2();
	cout<<"归并前"<<endl;
	cout<<"链表1:";
	VisitList(head1);
	cout<<"链表2:";
	VisitList(head2);
	cout<<"合并后的链表:";
	//Node *head=ListMerge(head1,head2);
	Node *head=ListMerge1(head1,head2);
	VisitList(head);
	FreeList(head);
	return 0;
}

          测试结果如下:


参考资料-------------《剑指offer》

  • 12
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值