排序 (第一部分)

新手刷题网站,快速入门!洛谷

排序


4.5

【深基9.例1】选举学生会

题目描述

学校正在选举学生会成员,有 n ( n ≤ 999 ) 名候选人,每名候选人编号分别从 1 到 n,现在收集到了 m (m ≤ 2000000 ) 张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。

输入格式

输入 n和 m以及 m个选票上的数字。

输出格式

求出排序后的选票编号。

输入样例

5 10
2 5 2 2 5 2 2 2 1 2

输出样例

1 2 2 2 2 2 2 2 5 5

思路

上去就无脑冒泡,结果TLE感动了,本题正确思路是采用计数排序

代码

#include<iostream>
using namespace std;
int a[2000];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++){
        int t;
        cin>>t;
        a[t]++;
    }
    int flag=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<a[i];j++){
            if(flag++) cout<<' ';
            cout<<i;
        }
    }
    return 0;
}

【模板】快速排序

题目描述

思路

每次迭代确保k值左边 <= k ,k 值右边 >= k, 即,每轮下来,确定一个k值的位置,快排模板是一定要记住的!!

这里简单记录一下位运算,>> 代表 右移

比如 6 的二进制为 0110,将其右移一位,变成 0011,即 3,因此 >>1 可以理解为 /2

代码

#include<iostream>
using namespace std;
int a[100010];
void quick_sort(int q[], int l, int r)
{
    //如果数组<=一个数,无需排序
    if (l >= r) return;
    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    quick_sort(a,0,n-1);
    for(int i=0;i<n;i++){
        if(i<n-1){
            printf("%d ",a[i]);
        }else{
            printf("%d",a[i]);
        }
    }
    return 0;
}

【深基9.例4】求第 k 小的数

题目描述

思路

无论是求第k小数还是第k大数,都是快排的延伸,我们知道快排一轮可以确定一个数的位置,进行迭代的过程,我们只需要知道第k小数在该数字的左边还是右边,然后迭代单边即可,记住快排模板,加以改进即可。

代码

#include <iostream>
using namespace std;
const int N = 5000010;
int q[N];
//该模板是从第1个数开始的
int quick_sort(int q[], int l, int r, int k)
{
    if (l >= r) return q[l];
    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j){
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    if (j - l + 1 >= k) return quick_sort(q, l, j, k);
    else return quick_sort(q, j + 1, r, k - (j - l + 1));
}

int main(){
    int n, k;
    scanf("%d%d", &n, &k);
    //题目要求从第0个数开始,因此k++
    k++;
    //如果求第k大数,只需赋值k为如下代码即可
    //k = n-k+1;
    for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
    cout << quick_sort(q, 0, n - 1, k) << endl;
    return 0;
}

[NOIP2006 普及组] 明明的随机数

题目描述

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N 个 1 到 1000 之间的随机整数 ( N ≤ 100 ),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。

思路

本题分为两步,第一步去重复,第二步排序,去重在输入过程中,遍历数组判断该数字是否存在即可

代码

#include <iostream>
using namespace std;
const int N = 110;
int q[N];
//排序直接用快排模板
int quick_sort(int q[], int l, int r)
{
    if (l >= r) return q[l];
    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j){
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }
    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}
int main(){
    int n;
    int len=1;
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ){
        int t;
        scanf("%d", &t);
        for(int j=0;j<len;j++){
            //如果输入的数字在数组中已存在,跳出本次循环
            if(q[j]==t) break;
            //否则在数组尾部插入该数字,并调整数组长度+1,确保数组尾部总有一个值为0的数字等待插入
            else if(q[j]==0){
                q[j]=t;
                len++;
                break;
            }
        }
    } 
    quick_sort(q, 0, len-2);
    //数组实际长度为len-1,在数字插入操作时,为了确保数组尾部总有一个值为0的数字,数组长度故意+1
    printf("%d\n", len-1);
    for (int i = 0; i < len-1; i ++ ){
        if(i<len-2) printf("%d ", q[i]);
        else printf("%d", q[i]);
    } 
    return 0;
}

4.8

[NOIP2007 普及组] 奖学金

题目描述

某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。

输入样例

6          //6组
90 67 80   //语数英成绩
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98

输出样例

6 265      //学号 总分
4 264
3 258
2 244
1 237

思路

本题与 帮贡排序 相似,在做帮贡排序时,我用两个数组做的,比较繁琐,本题采用结构体做法。首先题目要求:先按总成绩排序、再按语文成绩排序、再按学号排序。帮贡题是,先按帮贡排序,再按等级、再按经验,所以两道题很相似。本题中使用了sort大法 + 自定义比较函数,真香,具体步骤见代码。自定义比较函数,这里提供了两种方案,if else 和 三目表达式。

代码

#include <iostream>
#include<algorithm>
using namespace std;
struct Students{
    //学号
    int num;
    //语数英
    int c,m,e;
    //总分
    int sum;
};
Students s[310];
//比较函数
bool swp(Students s1,Students s2){
    //if else写法
    //总成绩
    if(s1.sum>s2.sum) return true;
    //语文成绩
    else if(s1.sum==s2.sum&&s1.c>s2.c) return true;
    //学号
    else if(s1.sum==s2.sum&&s1.c==s2.c&&s1.num<s2.num) return true;
    else return false;
    
    //三目表达式写法
    //return s1.sum>s2.sum?s1.sum>s2.sum:(s1.sum==s2.sum&&s1.c>s2.c?s1.c>s2.c:(s1.sum==s2.sum&&s1.c==s2.c&&s1.num<s2.num?s1.num<s2.num:0));
    //return 0;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
       scanf("%d%d%d",&s[i].c,&s[i].m,&s[i].e);
       s[i].num = i;
       s[i].sum = s[i].c + s[i].m + s[i].e;
    }
    sort(s+1,s+1+n,swp);
    for(int i=1;i<=5;i++){
       printf("%d %d\n",s[i].num,s[i].sum);
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值