排序算法小结:求第 k 小的数 洛谷P1923

排序算法小结:求第 k 小的数 洛谷P1923

本帖为本人刷完洛谷排序算法部分的总结,内容有排序算法的两个模板,以及sort和nth_element的使用。如有疏漏,欢迎指出。

题目描述

输入 n n n 1 ≤ n < 5000000 1 \le n < 5000000 1n<5000000 n n n 为奇数)个数字 a i a_i ai 1 ≤ a i < 10 9 1 \le a_i < {10}^9 1ai<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]);
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值