排序算法小结:求第 k 小的数 洛谷P1923
本帖为本人刷完洛谷排序算法部分的总结,内容有排序算法的两个模板,以及sort和nth_element的使用。如有疏漏,欢迎指出。
题目描述
输入 n n n( 1 ≤ n < 5000000 1 \le n < 5000000 1≤n<5000000 且 n n n 为奇数)个数字 a i a_i ai( 1 ≤ a i < 10 9 1 \le a_i < {10}^9 1≤ai<109),输出这些数字的第 k k k 小的数。最小的数是第 0 0 0 小。
请尽量不要使用 nth_element
来写本题,因为本题的重点在于练习分治算法。
输入格式
输出格式
样例 #1
样例输入 #1
5 1
4 3 2 1 5
样例输出 #1
2
思路:先运用sort或者手敲的排序算法,将输入数据排序,然后返回第k个数。
注意:由于本题最小的数为第0个数,所以第k小的数为第k+1个数
由于是小结,所以先把我最近用的最多的两个模板贴一下。
void quick_sort(int l,int r)//快速排序模板
{
if(l>=r)return;
int i=l-1,j=r+1,x=q[l+r>>1];
while(i<j>)
{
while(q[++i]<x);
while(q[--j]>x);
if(i<j>)swap(q[i],q[j]);
}
quick_sort(l,j);
quick_sort(j+1,r);
}
void merge_sort(int l,int r)//归并排序模板
{
if(l>=r)return ;
int mid=l+r>>1,k=0,i=l,j=mid+1;
merge_sort(l,mid);
merge_sort(mid+1,r);
while(i<=mid&&j<=r)
if(q[i]<=q[j])tmp[k++]=q[i++];
else tmp[k++]=q[j++];//tmp[]为全局变量,用来暂时存储数组
while(i<=mid)tmp[k++]=q[i++];
while(j<=r)tmp[k++]=q[j++];
for(i=l,j=0;i<=r;i++,j++)
{
q[i]=tmp[j];
}
}
高兴的是我终于算是掌握了排序的基本模板,但可惜这题如果用常规的排序方法,则会因为数据量过大而超时,只能AC60%的数据。注意到只需要输出第k小的数,所以我们可以采用分治的思想,代码实现如下。
#include <iostream>
using namespace std;
const int N=5001000;
int n,k;
int q[N];
int quick_sort(int l,int r,int k)
{
if(l==r)return q[l];//直接返回要找的数
int x=q[l+r>>1],i=l-1,j=r+1;
while(i<j)
{
while(q[++i]<x);
while(q[--j]>x);
if(i<j)swap(q[i],q[j]);
}
int sl=j-l+1;//快排每次将数组分为两块,左边为l到j,右边为j+1到r
if(k<=sl)return quick_sort(l,j,k);//要找的数在左边
else return quick_sort(j+1,r,k-sl);
}
int main()
{
cin>> n>> k;
for(int i=0;i<n;i++)scanf("%d",&q[i]);
cout<<quick_sort(0,n-1,k+1)<<endl;//直接输出答案
return 0;
}
除了分治思想和排序模板以外,我们还可以学会:sort和nth_element。
sort(first,last,cmp)对[first,last)范围内的数据进行排序。
在头文件< algorithm >中,cmp表示排序规则,可省略,默认为升序排序。
bool cmp(变量类型 a,变量类型 b)
{
if(xxx)return 1;//如果返回值为真,则为sort里面的“小于”(sort函数为非降序排序)
例:return a>b;(将较大的数据放在前面,因为如果a>b,则返回值为真,符合sort的“小于”)
}
nth_elment(first ,last)
在头文件< algorithm >中,默认为升序排序。
当采用默认的排序规则时,该函数可以从某个序列中找到第 n 小的元素 K,并将 K 移动到序列中第 n 的位置处。除此之外,整个序列经过 nth_element() 函数处理后,所有位于 K 之前的元素都比 K 小,所有位于 K 之后的元素都比 K 大。
nth_element(x,x+k,x+n,cmp)
//在[x,x+n)中寻找第k小的数(最小为1)。cmp可省略。
拿本题举个例子吧(以下为洛谷某位大佬的代码)
#include<bits/stdc++.h>
using namespace std;
int x[5000005],k;
int main()
{
int n;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&x[i]);
nth_element(x,x+k,x+n);
printf("%d",x[k]);
}