快速排序算法实现及原理分析
Input
5
1 3 2 5 4
Output
1 2 3 4 5
算法原理
对于a[0,n)数组元素的排序,通过分治思想转化为a[0,m)和a[m+1,n)的排序问题,程序中采用递归实现。
假设需要排序的区间为[l,r),升序排列。在递归调用前需要选择数组中的一个元素作为参考标准(记为pivot),将小于pivot的元素放在区间左边,大于pivot的元素放在区间右边,区间范围从[l,r)逐渐缩小。首先考虑右侧,从r开始向前找到比pivot小的元素,将该元素放入当前区间左侧(l位置);左侧从l开始向后找到比pivot大的元素,将该元素放入当前区间右侧(r位置)。重复上述过程直到l>=r。
在选取参考元素的同时,需要记录参考元素的数值,因为在上述的操作中,参考元素原先的位置会被新的数字覆盖。同时最后当l>=r时需要将参考元素的位置放在重合处(l或r)。
#include<iostream>
#include<random>
using namespace std;
int n;
int partition(int *a,int l,int r)
{
//cout<<"**********"<<endl;
//cout<<l<<" "<<r<<endl;
//for (int i=0;i<n;i++)
// cout<<a[i]<<" ";
//cout<<endl;
int num=l+rand() % (r-l);
int t=a[l];
a[l]=a[num];
a[num]=t;//这里随机选取参考元素,并将参考元素与区间左端点交换
r--;
int pivot=a[l];
while (l<r){
while (l<r && pivot<=a[r]) r--;
a[l]=a[r];
while (l<r && a[l]<=pivot) l++;
a[r]=a[l];
}
a[l]=pivot;
//for (int i=0;i<n;i++)
// cout<<a[i]<<" ";
//cout<<endl<<"**********"<<endl;
return l;
}
void qsort(int *a,int l,int r){
if (r-l<2) return;
int m=partition(a,l,r);
qsort(a,l,m);
qsort(a,m+1,r);
}
int main(){
cin>>n;
int *a=new int[n];
for (int i=0;i<n;i++)
cin>>a[i];
qsort(a,0,n);
for (int i=0;i<n;i++)
cout<<a[i]<<" ";
return 0;
}
快排中间过程输出
**********
0 5
1 3 2 5 4
4 3 2 1 5
**********
**********
0 4
4 3 2 1 5
1 2 4 3 5
**********
**********
2 4
1 2 4 3 5
1 2 3 4 5
**********
1 2 3 4 5
时间复杂度分析
对于每一个分治区间的排序,每次与选取的参考元素比较过程实际上遍历了整个区间
[
l
,
r
)
[l,r)
[l,r),而
r
−
l
<
n
r-l<n
r−l<n,所以用时不超过
O
(
n
)
O(n)
O(n)
由于分治的数量在理想情况下为
l
o
g
n
log n
logn级别,所以总的时间复杂度
O
(
n
l
o
g
n
)
O(nlog n)
O(nlogn)。但是由于每次划分的随机性,导致递归的层数可能会达到n,所以最坏情况下时间复杂度为
O
(
n
2
)
O(n^2)
O(n2)