快速排序与归并排序一样利用了分治思想,将序列分为两个总体有序子序列(即子序列A中所有元素都小于子序列B),再对子序列进行排序最后合并。
#include<iostream>
using namespace std;
void QuickSortJy(int a[],int l,int r){ //l,r为递归中当前序列的左右边界
if(l>=r) return; //递归结束条件:子序列只剩下一个元素,无需排序
//对子序列排序的具体思想为:取一个key值将序列分为小于key和大于key的两个子序列,然后重复以上步骤,即对两个子序列递归排序
int key=a[l]; //普通快速排序中key值一般为左右端点
int ll=l,rr=r; //ll为左游历指针,rr为右游历指针
while(ll<rr){ //当ll与rr相遇之时,则左右序列已排序好
//右边找小于key
while(a[rr]>key&&rr>ll) rr--; //注意rr>ll,若为rr>=ll,若ll未移动则会越界
//左边找大于key
while(a[ll]<=key&&ll<rr) ll++; //注意<=,否则出错
//此时ll为左子序列中大于key的元素,rr为右子序列中小于key的元素,则需要交换
int temp=a[rr];
a[rr]=a[ll];
a[ll]=temp;
}
//此时ll==rr且以此为分界点的左右子序列已经排好序,要先把Key值放到该位置,即将进入递归
a[l]=a[ll]; //!!!!注意把相遇位置的数字放回选择的端点处
//此时相遇处分析:无论是ll走过去找rr还是rr走过去找ll,相遇点的数字都小于key
a[ll]=key;
QuickSortJy(a,l,ll-1);
QuickSortJy(a,ll+1,r);
}
int main(){
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++) cin>>a[i];
QuickSortJy(a,0,n-1);
for(int i=0;i<n;i++) cout<<a[i]<<' ';
}
时间复杂度分析:
最坏情况:每次取的key都是最小或者最大数字,则递归下来的子序列可以看作一个只有左子树或者只有右子树的二叉树,共有n层,每一层指针都要遍历n次,所以时间复杂度为(n2)
若为最好情况:每次取得key值都是中位数,则每次将序列分为两个大小几乎相等的子序列,可以看作生成了一个完全二叉树,即有logn层,每一层遍历n/2,n/4,n/8...次,所以总时间复杂度为O(nlogn)
所以快速排序的时间复杂度在nlogn到n2之间