快速排序(Quicksort)算法
这个排序算法在面试题中基础遇到
虽然STL中有sort函数(自行了解)可以快速解决,
时间复杂度也相差无几,但是有些题目还是可以卡死sort排序。
如:求n个数第k大值(1<n<=1e8)
这个题目用sort是无法在一秒钟解决的。
当然用快速排序也无法解决,但是稍微改变一下就能解决。
所以今天我们来了解一下快速排序算法。
快速排序算法的时间复杂度为:
- 平均O(nlogn)
- 最差O(N2)
快速排序算法的大致过程
快速算法是基于递归实现,先确定一个基准数(假设取中间位置的数x=a[(l+r)/2])。
定义两个指针(i,j)i从头开始,j从尾开始。
当a[i]大于x时停止,当a[j]小于x时停止,判断当前i是否小于j,如果是就交换位置。
以此类推,当i>=j时退出循环。
此时的状态为
我们再分为两边进行递归处理,处理过程也是和上面一样。
因为经过以上操作左、右两边区间的数虽然排序不同,但是他们所在的区间已经不会改变
代码实现过程如下
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int a[N];
void quick_sort(int l,int r){
if(l>=r)return ;
int i=l-1,j=r+1,mid=a[(l+r)/2];//指定两个指针i,j,和基准数mid
while(i<j){//这里如上所说的操作
while(a[++i]<mid);
while(a[--j]>mid);
if(i<j)swap(a[i],a[j]);
};
quick_sort(l,j);//递归左边处理
quick_sort(j+1,r);//递归右边处理
}
int main{
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
quick_sort(0,n-1);
for(int i=0;i<n;i++){
cout<<a[i]<<" ";
}
return 0;
}
然而对于开头所说的例题(找第k大数),如果数据过大的是无法在1s内结束操作,
因此对快速算法模板代码进行改动,时间复杂度可以优化到O(n)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
namespace IO{
inline LL read(){
LL o=0,f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){o=o*10+c-'0';c=getchar();}
return o*f;
}
}using namespace IO;
const int N=1e6+7;
int a[N];
int quick_sort_th(int l,int r,int k){
if(l>=r)return a[l];//当l==r时,就返回当前数
int i=l-1,j=r+1;
int mid=a[l+r>>1];
while(i<j){
while(a[++i]<mid);
while(a[--j]>mid);
if(i<j)swap(a[i],a[j]);
};
if(k<=(j-l+1))return quick_sort_th(l,j,k);//要查找的第k大数在左边区间就只需要去左区间找
else return quick_sort_th(j+1,r,k-(j-l+1));//要查找的第k大数在左边区间就只需要去右区间找,并且第k大的数在右区间的排名是k-左区间总数(j-l+1)
}
int main(){
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>a[i];
}
cout<<quick_sort_th(0,n-1,k)<<endl;
return 0;
}