快速排序是分治策略的一个应用。
算法思想就是基准元素的划分,这点可以参考书上的分析。
主要给出快速排序算法的分析:
快速排序算法的时间主要耗费在划分操作上,并与划分是否平衡密切相关。对于长度为n的待排序序列,一次划分算法Partition需要堆整个待排序序列扫描一遍,其所需要的计算时间显然为O(n)。
下面从三种情况来讨论一下快速排序算法的时间复杂度。
(1)最坏时间复杂度
最坏情况是每次划分选取的基准元素都是在当前待排序序列中的最小(或最大)元素,划分的结果所基准元素左边的子序列为空(或右边的子序列为空),而划分所得的另一个非空的子序列中元素个数仅仅比划分前的排序序列中元素个数少1个。
在这样的情况下,快速排序算法必须做n-1次划分,那么算法的运行时间T(n)的递归形式为:
O(1) n = 1
T(n) =
T(n-1) + O(n) n > 1
因此,快速排序算法的最坏时间复杂度为O(n*(n+1)/2)=O(n*n)
(2)最好时间复杂度
在最好情况下,每次划分所去的基准元素都是当前待排序序列的“中间值”,划分的结果所基准元素的左右两个子序列的长度大致相同,此时,算法的运行时间T(n)的递归形式为:
O(1) n = 1
T(n) =
2 T(n/2) + O(n) n > 1
解出后得到最好时间复杂度为O(nlogn).
(3)平均时间复杂度
在平均情况下,采用归纳法可求得T(n)的数量级也为O(nlogn).
尽管快速排序的最坏时间复杂度为n*n,但是就平均性能来说,它是基于元素比较的内部排序算法中速度最快的,因此得名:Quick_Sort
快速排序的空间复杂度
因为快速排序采用递归执行,所以需要一个栈来存放每一层递归调用的必要信息,其最大容量与递归调用的深度一致。最好情况下,若每次划分都比较均匀,则递归树的高度为O(logn),故递归需要栈空间为O(logn)。最坏情况下,递归树的高度为O(n),所需要的栈空间为O(n)。平均情况下,所需要的栈空间为O(logn)。
给出测试代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N = 10;
int arr[N];
/******************快速排序稳定版本*************************************/
void QuickSort(int low, int high)
{
if(low >= high)
return ;
int i, j, pivot;
i = low, j = high, pivot = arr[(high + low) >> 1]; //每次取中间元素作为基准
swap(arr[low], arr[(high + low) >> 1]);
while(i < j)
{
while(i < j && arr[j] >= pivot) --j;
arr[i] = arr[j];
while(i < j && arr[i] <= pivot) ++i;
arr[j] = arr[i];
}
arr[i] = pivot;
QuickSort(low, i - 1); //递归左边
QuickSort(j + 1, high); //递归右边
}
/*************************************************************************/
/******************快速排序一般版本(可求第K大元素)*****************/
int Partition(int low, int high)
{
int i, j, pivot;
i = low, j = high, pivot = arr[low];
while(i < j)
{
while(i < j && arr[j] >= pivot) --j;
if(i < j) swap(arr[i++], arr[j]);
while(i < j && arr[i] <= pivot) ++i;
if(i < j) swap(arr[i], arr[j--]);
}
return j; //返回基准元素位置
}
void Quick_Sort(int low, int high)
{
int pivotpos;
if(low < high)
{
pivotpos = Partition(low, high);
Quick_Sort(low, pivotpos - 1); //基准左递归排序
Quick_Sort(pivotpos + 1, high); //基准右递归排序
}
}
int select(int low, int high, int k)
{
int pivotpos, num;
if(low == high)
return arr[high];
pivotpos = Partition(low, high);
num = pivotpos - low + 1; //左边元素个数
if(k == num)
return arr[pivotpos];
else if(k < num)
return select(low, pivotpos - 1, k);
else
return select(pivotpos + 1, high, k - num);
}
/*************************************************************************/
int main()
{
int k;
cout<<"输入10个数字:"<<endl;
for(int i = 0; i < 10; ++i)
scanf("%d", &arr[i]);
QuickSort(0, 9);
cout<<"快速排序后:"<<endl;
for(int i = 0; i < 10; ++i)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"输入第K大元素:"<<endl;
cin>>k;
cout<<select(0, 9, k)<<endl;
return 0;
}