快速排序的优化

快速排序的优化

1. 优化枢轴的选取:

    我们在快速排序中,我们选择的枢轴应该位于整个数组的中间位置,这样可以让数组一次性移动较多的数目,提高快速排序的效率;但是如果我们选择的枢轴是整个数组的最大值或者最小值,那么每次进行快速排序只能移动一个元素,大大降低了快速排序的速度,与冒泡排序的速度相差无几;
   所以我们优化快速排序,可以是优化枢轴的选取。

   (1)三数取中法: 即选取三个关键字进行排序,将中间数作为枢轴,一般是取最左端,最右端和中间位置的数,最后选择中间数作为枢轴,这样可以保证最后选择的枢轴肯定不是最小值或者最大值。;

int pivotkey;
int mid = low + (high - low)/2;
if(L->[low] > L->[high])  //交换左端和右端的数
	swap(L, low, high);
if(L->[m] > L->[high])  //交换中间和右端的数
	swap(L, mid, high);
if(L->[low] > L->[mid])  //交换左端和中间的数
	swap(L, low, mid);

privotkey = L->[mid] //最后选取中间的数

缺陷: 三数取中对于小数组可以选到一个好的枢轴,但对于大数组来说并没有多大用处;
(2)九数取中法: 它先从数组中分三次取样,每次取三个数,三个样品各取出中数,然后从这三个中数当中再取出一个中数作为枢轴,这样就更加保证取到的枢轴是比较接近中间值的数。

2.优化不必要的交换:

   在快速排序的过程中,每一趟中都要进行一定次数的交换,但是只有最后一次的交换是有用的,即把枢轴放到恰当的位置(左边的值均比枢轴小,右边的值均比枢轴大),所以排序过程中,除了最后一次进行交换,其他才用赋值操作即可;这样就少了多次交换数据的操作,在性能上又得到了部分的提升。

优化部分的代码:

int Partition(int* arr, int low, int high)
{
	int pivotkey;
	int mid = low + (high - low)/2;
	if(L[low] > L[high])  //交换左端和右端的数
		swap(L, low, high);
	if(L[m] > L[high])  //交换中间和右端的数
		swap(L, mid, high);
	if(L[low] > L[mid])  //交换左端和中间的数
		swap(L, low, mid);
	
	privotkey = L[mid] //最后选取中间的数
	L[0] = privotkey;
	while(low < high)
	{
		while(low < high && L[high] >= privotkey)
			high--;
		L[low] = L[high]  //赋值而不是交换
		while(low < high && L[low] <= privotkey)
			low--;
		L[high] = L[low]; //赋值而不是交换
	} 
	L[low] = L[0]; //最后交换到合适的位置
	return low;
}

3.优化小数组时的排序方案:

   在数组非常小的情况下,快速排序反而不如直接插入排序(直接插入排序是简单排序中效率最好的),所以在数组较小的情况下,我们可以使用直接插入排序,而在数组较大的情况下使用快速排序。
   其原因是: 在处理大量数据的时候,快速排序中递归操作对于性能的影响相对于它的整体算法优势而言是可以忽略的,但如果数组只有几个记录需要排序时,递归操作对于性能的影响将会格外突出,所以要在数据量小的时候使用直接插入排序;

4.优化递归操作:

    当待排序的序列及其不平衡的时候,递归的深度趋近于n,而不是平衡时的log(n)。而且栈的空间而是有限的,每次递归调用都会耗费一定的栈空间,函数的参数越多,每次递归消耗的空间也就越多,如果减少了递归的操作,就能大大提升性能。所以可以使用尾递归来优化性能
void Qsort2(int *L, int low, int high)
{
	int pivot;
	while(high < low)
	{
		pivot = Partition(L, low, high); //尾递归的操作
		QSort2(L, low, pivot-1);
		low = pivot + 1;
	}
}
   采用了迭代而不是递归的方法可以缩减堆栈的深度,从而提高了整体性能。

此文为阅读笔记,内容来自于《大话数据结构》。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值