链表的归并排序

10 篇文章 0 订阅

一开始写链表的排序代码是因为在《算法》里面看到说自低向上的归并算法比较适合链表结构的数据,但是里面没有给出代码,于是就自己拿来练手。

链表排序与数组排序最大的不同就是随机访问代价太高,每次都需要遍历。

归并的思想就是把大的数据分成小数据,先将小数据排序,然后再并起来。

而自低向上的归并,是一变二,二变四...最终变成一个整体(具体请参考算法书)

对于链表来说,两个小链表的合并与两个数组的合并没有太大区别,都是两边同时遍历进行比较然后取较小(大)值,形成一个大的有序序列。

不同是如何将大序列分成小序列,数组可以直接把下表均分,而链表则需要遍历一遍才能均分。

我看到网上的实现,好像也都是这么做的:

 《用归并排序对链表进行排序

用归并排序对链表进行排序


其中的FrontBackSplit()函数就是用快慢指针进行遍历,然后分成2半。

不过每次分完之后链表的长度都会变小,所以其实花费的时间还是可以接受的。

然后我自己写了一个实现方法,是用队列保存各个小序列的头指针,从而避免每次找头指针的消耗。这是一开始看到题目时候的思路,但是现在回过头看,感觉为了节省这点时间额外增加了这么多的空间消耗(N/2长度的队列)似乎有点不值。不过还是把代码贴上来:

两个链表的合并我就直接用了上面那片文章里的函数了,写得非常简洁:

myNode* mergeForList(myNode* a, myNode* b)
{
	myNode* result = nullptr;
	if (a == nullptr)
	return(b);
	else if (b==nullptr)
	return(a);

  /* 使用递归调用的方法 */

	 if (a->val <= b->val)
	{
     result = a;
     result->next = mergeForList(a->next, b);
	 }
	 else	  
	 {
     result = b;
     result->next = mergeForList(a, b->next);
	 }
	 return(result);

}

myNode定义:

class myNode
{
public :
	int val;
	myNode* next;
};


归并排序的实现:

void mergeSort2ForList(myNode* &head)//链表的归并排序
{
	if(head==nullptr) return;
	queue<myNode*> ptQueue;

	myNode *head1, *head2, *head3;
	head1=head;
	//先两两合并,如1和2合并,3和4合并,合并完把结尾指向空指针,并把头指针加入队列
	while(head1!=nullptr&&head1->next!=nullptr)
	{
		head2=head1->next;
		head3=head2->next;
		if(head1->val <=head2->val)
		{//如果小序列里的第一个节点比较小,那么不需要交换位置,直接把第一个节点作为头指针入队列,第二个节点指向空
			ptQueue.push(head1);
			head2->next=nullptr;
		}
		else
		{//如果第二个比较小,则交换位置
			ptQueue.push(head2);
			head2->next=head1;
			head1->next=nullptr;
		}
		head1=head3;
	}
	if(head1!=nullptr)//说明是单数个数据,把最后一个数据直接入队列
		ptQueue.push(head1);

	//开始两两合并队列里的序列,注意合并之后的新序列的头指针会继续入队列
	while(ptQueue.size()!=1)
	{//合并后的长度越来越长,可合并的序列也越来越少
	//当合并的序列只有一个时,退出循环
		head1=ptQueue.front();//取出第一个序列
		ptQueue.pop();
		head2=ptQueue.front();//取第二个序列		
		ptQueue.pop();
		ptQueue.push( mergeForList(head1, head2));//合并之后的新序列的头指针继续入队列
	}
	head=ptQueue.front();//排序后的头指针

}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值