快速排序(Quicksort)

0)引论

人如其名,快速排序之所以称之为快速排序就是因为在实践中,这个算法是最快的排序算法。它的平均运行时间为O(NlogN)。最坏的时间复杂度为O(N^2)。虽然像堆排序,归并排序的时间复杂度比较低,但是他们的实际运行时间并不比快速排序快,反而由于有一些拷贝的进程,使运行时间变得很慢。快速排序也是一种divide-and-conquer策略。


1)快速排序基本步骤:

a) 如果数据集S中的元素个数为0或1,则返回。

b) 选取S中的一个元素v,我们称这个元素v为pivot。

c) 把S-{v}分成两部分S1 = {x<=v} ,S2 = {x>=v}。

d) 返回quicksort(S1) , v, quicksort(S2)。



2)pivot的选择

pivot的选择是一个很大的问题。因为pivot直接影响到分开的两组数据的个数,而如果这两组数据是不均衡的,则会严重影响到算法的运行速度。举个例子来说,如果每次选择的pivot 都是最大值的话,那么这个快速排序算法相当于插入排序

pivot的选择有以下几种

a) 选取第一个值。这种算法适用于随机分布的数据。如果是一个有序的序列,那么这种选取方式就是一个灾难啊,将会不断的递归,也没有什么本质的提高

b) 随机选取一个值。这种方法也是看运气,如果选择了一个好的值就没有问题。但是如果选的值比较差,就会比较糟糕

c) 随机选取3个值,取中间值。这种方法对差值的风险抵抗能力比较强。一种常用的方法是选择数据的第一个值,中间的值,最后一个值。然后取这3个值得中间值。

代码片段:

ElementType Median3(ElementType A[], int Left, int Right)
{
	int Center = (Left  + Right)/2;
	if(A[Left]>A[Center])
		Swap(&A[Left],&A[Center]);
	if(A[Left]>A[Right])
		Swap(&A[Left],&A[Right]);
	if(A[Center]>A[Right])
		Swap(&A[Center],&A[Right]);
	Swap(&A[Center],&A[Right-1]);
	return A[Right-1];
}

3)算法描述

这里,我们通过一个例子说明一下快速排序算法。

待排序数据为(8,34,51,21,18,64,26,32)首先利用上面的方法找到pivot为21,然后把pivot与A[N-1]=26交换位置。然后设定两个游标i,j。i向右滑动直到遇到大于pivot的值处停止,j向左滑动直到遇到小于pivot的值处停止,然后交换i,j对应的元素,然后继续上面的步骤知道i>j,然后交换i与pivot对应的元素。这样就把待排序数据集分成了两部分,然后递归调用上面的算法,最终得到排好序的数据。这里可能会有一个问题就是相等的元素,这将是一个特殊情形,例如数据中有几个值与pivot相等,那么当游标运动到了这几个位置时应该怎么办呢?游标继续向前走,越过这些值。


代码描述:

#define Cutoff (3)
void Qsort(ElementType A[], int Left, int Right)
{
	int i,j;
	ElementType pivot;
	if(Left + Cutoff <= Right)
	{
		pivot = Median3(A,Left,Right);
		i=Left;j=Right-2;
		for(::)
		{
			while(A[++i]<pivot){}
			while(A[--j]>pivot){}
			if(i<j)
				Swap(&A[i],&A[j])
			else
				break;
		}
		Swap(&A[i],&A[Right-2]);
		Qsort(A,Left,i-1);
		Qsort(A,i+1,Right);
	}
	else
		InsertionSort(A+Left,Right-Left+1);
}


void QuickSort(ElementType A[], int N)
{
	Qsort(A,0,N-1);
}

4)到底应该选取什么样的排序算法

我们已经介绍了几种排序方法,那么到底应该怎样选取排序方法呢?如果排序数目比较大,那么尽量用快速排序,如果数据量比较小,还是用插入排序或希尔排序比较好,因为这个两种方法比较简单,更重要的是在小数据量的排序中,快速排序的递归运算更加耗时。如果数据量相当大以至于无法完全在内存中运行,那么建议用归并排序,归并排序主要应用于外部排序中。当然还有一种桶排序,这个排序的速度相当迅速,但是限制条件太多,要求待排序数据为不大于某一值得正整数,约束性太强了。


5)排序方法的下界

任何只利用比较方法来排序的方法的最坏情况下需要


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
快速排序QuickSort)是一种高效的排序算法,它基于分治策略。该算法首先选择一个元素作为基准值(pivot),然后将待排序数组按照基准值分成两个子数组,一边是所有小于基准值的元素,另一边是所有大于等于基准值的元素。然后对两个子数组分别递归地进行快速排序,最后将两个子数组合并起来即可得到完整的有序数组。 以下是使用C++实现快速排序的代码: ```cpp void quickSort(vector<int>& nums, int left, int right) { if (left >= right) return; // 递归终止条件 int pivot = nums[left]; // 选择第一个元素作为基准值 int i = left, j = right; while (i < j) { // 一趟快速排序 while (i < j && nums[j] >= pivot) j--; // 从右往左找到第一个小于基准值的元素 if (i < j) nums[i++] = nums[j]; // 将该元素放入左半部分 while (i < j && nums[i] < pivot) i++; // 从左往右找到第一个大于等于基准值的元素 if (i < j) nums[j--] = nums[i]; // 将该元素放入右半部分 } nums[i] = pivot; // 将基准值放入合适的位置 quickSort(nums, left, i - 1); // 递归地对左半部分进行快速排序 quickSort(nums, i + 1, right); // 递归地对右半部分进行快速排序 } ``` 其中,`nums`表示待排序数组,`left`和`right`表示当前子数组的左右边界(初始时应为0和`nums.size()-1`)。我们首先选择第一个元素作为基准值,然后使用双指针i和j在数组中进行一趟快速排序,将小于基准值的元素放入左半部分,将大于等于基准值的元素放入右半部分。最后将基准值放入合适的位置,并递归地对左右两个子数组进行快速排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值