写给自己看的单链表(4):快速排序

!!!Attention:以下操作中的单链表均带有头结点!!!
参考了这三篇文章:
单链表快速排序算法的实现
单链表的快速排序
单链表的快排实现
快速排序的思路是:首先,选取一个pivot;然后以pivot作为基准,对待排序的数据进行分区,得到两个部分,一个部分的数据均小于pivot,另一个部分的数据均大于pivot,然后对这两个部分再进行之前的操作,直至排序完成。
对数组来说,pivot通常会选取位于中间的数据,然后用两个指针分别从头、尾两端向中间移动。
但是对于单链表来说,由于只能从头到尾单方向进行移动,所以其快速排序的实现方式有所不同,取第一个节点为pivot(这里要注意开区间和闭区间的问题,下面细说),指针p从pivot开始向后移动,指针q从pivot->next开始向后移动,最后一步是交换pivot和p的值,最终呈现的结果是:从头结点至p-1(含p-1)之间的数据均小于pivot,从p+1(含p+1)至q之间的值均大于pivot。
用一个例子来看看Partition函数的思路:
example
下面看一下不同区间表达式下的代码,开区间和闭区间导致代码不同的思路来自于这篇文章:你常写的二分查找,真的是没有bug吗?

1.左闭右开,初始区间为 [head->next,NULL)
这是比较省事的一种表达方式。首先看QuickSort函数的循环条件,当left != right时继续排序,借用上面那篇文章中的一个例子来说就是:

由于我们采用的是左闭右开表示法,也就是 区间为 [left ,right) 且left == right 循环停止,,如果用个例子来解释,大家就会豁然开朗了, 假如[ left=4, right=4),此时用左闭右闭来解释的话,区间实际上是出现了右边界=3 , 左边界=4 , 这种情形,右边界 < 左边界,这意味着区间长度<=0 了,无法继续了。

在迭代的过程中,仍然要保持区间是左闭右开的。在第一次分区后,数据的两个部分分别表示为 [head->next,par)[par->next, NULL),所以迭代的语句为QuickSort(head, left, par); QuickSort(head, par->next, NULL);
注意Partation函数中的语句也要根据区间的左闭右开性质来写。

void QuickSort(Lnode *head, Lnode *left, Lnode *right) //left is head->next, right is null
{
	if ( left != right) {	//ATTENTION!!!
		Lnode *par = Partation(left, right); 
		QuickSort(head, left, par);
		QuickSort(head, par->next, NULL);
	}
}

Lnode *Partation(Lnode *left, Lnode *right)
{
	if (left == right)
		return left;
	
	Lnode *p, *q;
	eletype pivot = left->data;	
	p = left;
	q = p->next;
	while (q != right) {
		if (q->data < pivot) {
			p = p->next;
			SwapData(p, q);
		}
		q = q->next;
	}
	SwapData(left, p);
	return p;
}

void SwapData(Lnode *p, Lnode *q)
{
	eletype tmp;
	tmp = p->data;
	p->data = q->data;
	q->data = tmp;
}

2.左开右开,初始区间为 (head,NULL)
这种表达方式使得调用函数时比较方便,因为参数直接就是head和NULL,但是写法比上一种稍麻烦了一点点。
QuickSort函数的循环条件发生了改变,当left->next != right时继续排序。在第一次分区后,数据的两个部分分别表示为 (head,par)(par, NULL),所以迭代的语句为QuickSort(head, left, par); QuickSort(head, par, NULL);,Partation函数中的语句也要根据区间的左开右开性质来写。

void QuickSort(Lnode *head, Lnode *left, Lnode *right)
{
	if (left->next != right) {	
		Lnode *par = Partation(left, right);
		QuickSort(head, left, par);
		QuickSort(head, par, NULL);
	}
}

Lnode *Partation(Lnode *left, Lnode *right)
{
	if (left->next->next == right)
		return left->next;
	
	Lnode *p, *q;
	eletype pivot = left->next->data;	
	p = left->next;
	q = p->next;
	while (q != right) {
		if (q->data < pivot) {
			p = p->next;
			SwapData(p, q);
		}
		q = q->next;
	}
	SwapData(left->next, p);
	return p;
}

void SwapData(Lnode *p, Lnode *q)
{
	eletype tmp;
	tmp = p->data;
	p->data = q->data;
	q->data = tmp;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值