归并排序:nlogn
核心思想:递归分治,每次先把左右两个区间排好序,然后合并
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
int n,k,a[N],t[N];
int read(){
int num=0,f=1;char ch=getchar();
while(!isdigit(ch)){
f=-1;ch=getchar();
}
while(isdigit(ch)){
num=num*10+ch-'0';ch=getchar();
}
return num*f;
}
void gbsort(int l,int r){
if(l==r) return;
int mid=l+r>>1;
gbsort(l,mid);gbsort(mid+1,r);
int le=l,ri=mid+1,tmp=l;
while(tmp<=r){
while(a[le]<=a[ri]&&le<=mid&&ri<=r) t[tmp++]=a[le++];
while(a[le]>a[ri]&&ri<=r&&le<=mid) t[tmp++]=a[ri++];
while(le>mid&&ri<=r) t[tmp++]=a[ri++];
while(ri>r&&le<=mid) t[tmp++]=a[le++];
}
for(int i=l;i<=r;++i) a[i]=t[i];
return;
}
int main(){
n=read(),k=read();
for(int i=1;i<=n;++i) a[i]=read();
gbsort(1,n);
printf("%d\n",a[k+1]);
return 0;
}
快速排序:nlogn
核心思想:在区间内中间找一个数,把小于他的都放在他的左边,大于他的都放在他的右边。这个代码实现难在你不知道你找的那个数,有几个比他小,几个比他大。但其实不用想那么多,设置两个指针从左到右,如果左边的数小于中间的,就指针向右移动,右指针同理。当无法移动的时候,有可能指针在中间的数两侧,那交换之后仍然满足条件。也有可能是一个指针到了当前中间的这个数,这样代表小于中间这个数的数字更多或者大于这个中间数的数字更多,仍然做交换操作即可。直到指针相遇,然后我们再递归分治左右两个区间。
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
int n,k,a[N];
int read(){
char ch=getchar();
int num=0,f=1;
while(!isdigit(ch)){
f=-1;
ch=getchar();
}
while(isdigit(ch)){
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}
void qsort(int l,int r){
if(l>=r) return;
int i=l,j=r,mid=a[l+r>>1];
while(i<=j){
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j){
swap(a[i],a[j]);
i++,j--;
}
}
qsort(l,j);qsort(i,r);
}
int main(){
n=read(),k=read();
for(int i=1;i<=n;++i) a[i]=read();
qsort(1,n);
printf("%d\n",a[k+1]);
return 0;
}
然后如果是求第k小的数,用快速排序,类似二分查找的方法,只分治左右其中一个区间,我们就可以O(n)的复杂度解决问题。