acm新手小白必看系列之(2)——基本排序及cmp函数精讲及例题

acm新手小白必看系列之(2)——排序及cmp函数

sort排序

  1. sort是c++自带函数 复杂度 n*log(n) 包含在头文件
    #include的c++标准库里 函数有三个参数
    1.要排序的数组的起始地址
    2.数组的结束地址
    3.第三个参数是排序的方法,可以不写,默认是从小到大
  2. sort(a,a+n) -----默认从小到大排序 比如 int a[ ]={2,7,1,5,0}
  3. 我们可以写成
    sort(a,a+5)

从小到大排序可以写成
sort(a,a+n,less<要进行排序的数据类型>())
从大到小排序可以写成
sort(a,a+n,greater<要进行排序的数据类型>())

结构体排序
我们定义一个结构体
typedef struct stu
{ int xuehao;
int chengji;
}stu;
stu p[20];
如果我们要按成绩排序
可以写成sort(p,p+20,cmp1)

cmp函数写法

比如我们要按成绩排序从高到低
bool cmp1(stu a,stu b)
{
return a.chengji>b.chengji;
}

  • 刚才的int数组从小到大排序,我们还可以写成

bool cmp2(int a,int b)
{ return a<b;
}

  • 还有一种情况

struct node
{ int x,y;
}a[10];

  • 如果们要求a数组按x值的从小到大排序,若x相等,按y的从小到大排,我们写成:

bool cmp3(node a,node b)
{ if(a.x==b.x)
return a.y<b.y;
else return a.x<b.x;
}
(这个会经常用)
**

桶排序

  • 桶排序,是一种计数排序
  • 就是把要排序的数据放到桶里,我们需要设置桶的数量(即排序的范围),把数据放到与之匹配的桶里,改变记录桶有多少个数据的变量(一定要在装数据之前初始化),输出时要遍历所有桶,选数据不为0的数据输出,按编号输出即可。
    (不是排序的排序主要用于标记,读者自悟)
    举个例子:小明班上五个同学,他们期末考试的成绩分别是5分,3分,5分,2分,8分(满分10分)
    我们要把他们的成绩排序
    首先,我们可以想到可以用sort排序
    另一种方法:分数的取值是0~10分,我们可以定义一个一维数组a[11],刚开始我们把这个数组里的所有元素初始化为0 ,表示这些分数还没有人得过,比如a[0]=0,即还没有人获得0分…a[10]=0,即还没与人获得10分。
    下面开始处理这五个人的分数
    5分,3分,5分,2分,8分
    第一个人5分,我们把a[5]的值改为1,意思是5分出现过一次
    在这里插入图片描述
    第二个人是3分,我们把a[3]的值改成1,意思是3分出现过1次
    在这里插入图片描述

第三个人是5分,我们把a[5]更新为2,意思是有两个人得5分
第四个人是2分,我们把a[2]从0更新为1,即有一个人得2分
第五个人得8分,我们把a[8]从0更新为1
最后得到
在这里插入图片描述
经典的图如下
在这里插入图片描述
代码如下

#include<stdio.h>
int main()
{
    int a[11],i,j;
    for(i=0;i<11;i++)
    {
        a[i]=0;
    }
    int n;//人数
    scanf("%d",&n);
    int t;//用t接收分数
    for(i=0;i<n;i++)
    {
       scanf("%d",&t);
       a[t]++;
    }
    for(i=0;i<11;i++)
    {
        for(j=1;j<=a[i];j++)
        {
            printf("%d ",i);
        }
    }
    printf("\n");
    return 0;
}
//若是从大到小输出则把for(i=0;i<11;i++)改成for(i=10;i>=0;i--)即可

1·谁是第k名
在一次考试中,每个学生的成绩都不相同,现知道了每个学生的学号和成绩,求考第k名学生的学号和成绩。
Input
第一行有两个整数,分别是学生的人数n(1≤n≤100),和求第k名学生的k(1≤k≤n)。
其后有n行数据,每行包括一个学号(整数)和一个成绩(浮点数),中间用一个空格分隔。
Output
输出第k名学生的学号和成绩,中间用空格分隔。(注:请用%g输出成绩
Sample Input
5 3
90788001 67.8
90788002 90.3
90788003 61
90788004 68.4
90788005 73.9
Sample Output
90788004 68.4

  • 先讲解一下%g
    %g用来输出实数,它根据数值的大小,自动选f格式或e格式(选择输出时占宽度较小的一种),且不输出无意义的0。即%g是根据结果自动选择科学记数法还是一般的小数记数法
    printf("%g\n", 0.00001234);
    printf("%g\n", 0.0001234);
    printf("%.2g\n", 123.45);
    printf("%.2g\n", 23.45);
    上面四句输出结果为:1.234e-050.00012341.2e+0223对于指数小于-4或者大于给定精度的数值,按照%e的控制输出,否则按照%f的控制输出.

  • 转换说明及作为结果的打印输出%a 浮点数、十六进制数字和p-记数法(C99)%A 浮点数、十六进制数字和p-记法(C99)%c
    一个字符 %d 有符号十进制整数 %e 浮点数、e-记数法%E 浮点数、E-记数法%f 浮点数、十进制记数法
    %g 根据数值不同自动选择%f或%e.%G 根据数值不同自动选择%f或%e.%i 有符号十进制数(与%d相同)%o
    无符号八进制整数%p 指针 %s 字符串%u 无符号十进制整数%x 使用十六进制数字0f的无符号十六进制整数
    %X 使用十六进制数字0f的无符号十六进制整数%% 打印一个百分号 使用printf ()函数 printf()的基本形式:
    printf(“格式控制字符串”,变量列表)

  • 跑题了哈,看代码

#include <bits/stdc++.h>
using namespace std;
struct j//名字都随便定义的
{
    string num;
    double mark;
} p[101];
bool cmp(j a,j b)
{
    return a.mark>b.mark;//cmp函数
}
int main()
{
    int n,k,i;
    cin>>n>>k;
    for(i=0; i<n; i++)
        cin>>p[i].num>>p[i].mark;
    sort(p,p+n,cmp);//sort排序
    printf("%s %g\n",p[k-1].num.c_str(),p[k-1].mark);
    return 0;
}

2.取奇数
给定一个长度为N(不大于500)的正整数序列,请将其中的所有奇数取出,并按升序输出
Input
共2行:
第1行为 N;
第2行为 N 个正整数,其间用空格间隔。
Output
增序输出的奇数序列,数据之间以逗号间隔。数据保证至少有一个奇数。
Sample Input
10
1 3 2 6 5 4 9 8 7 10
Sample Output
1,3,5,7,9

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n,i,a[510];
    while(scanf("%d",&n)!=-1)
    {
        for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
        sort(a+1,a+n+1);//sort函数
        for(i=1;i<=n;i++)
        {
            if(a[i]%2==1)//奇数判断
            {
                if(i==1)
                printf("%d",a[i]);
                else 
                printf(",%d",a[i]);//注意输出格式
            }
        }
        printf("\n");
    }
    return 0;
}

3·字典序
给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。
Input
第一行为n (0 < n < 20),表示班里的学生数目;
接下来的n行,每行为每个学生的名字和他的成绩, 中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大于100的非负整数。
Output
把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。
Sample Input
4
Kitty 80
Hanmeimei 90
Joey 92
Tim 28
Sample Output
Joey 92
Hanmeimei 90
Kitty 80
Tim 28

#include <bits/stdc++.h>
using namespace std;
struct node
{
    string name;
    int mark;
} p[21];
bool cmp(node a,node b)
{
    if(a.mark!=b.mark)
    return a.mark>b.mark;
    else return a.name<b.name;
}
int main()
{
    int i,n;
    cin>>n;
    for(i=0; i<n; i++)
        cin>>p[i].name>>p[i].mark;
    sort(p,p+n,cmp);
    for(i=0; i<=n-2; i++)
        printf("%s %d\n",p[i].name.c_str(),p[i].mark);
    printf("%s %d",p[n-1].name.c_str(),p[n-1].mark);
    return 0;
}

3·前k大的数和
羽裳有n个数,她想知道前k大的数的和为多少
Input
首先输入两个数n,k,代表有n个数,求前k大的和,接下来输入n个数,这n个数或是0或是1.
1<=k<=n<=1000
Output
输出一个数,为前k大的和
Sample Input
5 3
0 0 1 0 1
Sample Output
2

#include<bits/stdc++.h>
using namespace std;
int n,k,a[1005];
bool cmp(int x,int y)
{
    return x>y;
}
int main()
{
    while(~scanf("%d%d",&n,&k))
    {
        for(int i=1; i<=n; ++i)
        scanf("%d",a+i);
        sort(a+1,a+1+n,cmp);
        long long ans=0;
        for(int i=1; i<=k; ++i)
            ans+=a[i];
        cout<<ans<<endl;
    }
    return 0;
}

4·前k大的数和的进阶
羽裳有n个数,她想知道前k大的数的和是多少
Input
输入n,k代表有n个数,求前k大的和,之后输入n个数,第i个数为a[i]
1<=n<=10000000(1e7)
1<=k<1000
对任意的i
1<=a[i]<=100000(1e5)
Output
输出一个数ans,ans是前k大数的和
Sample Input
2 1
99999 1
Sample Output
99999
Hint
排序会超时

本题就是桶排序,只要想到从大到小开始统计有每个数出现几次就行!
例如:
100 100 99 99 99 88 88 88 88 77 77 66
1002993884772661个
从大到小  凑齐K 个数,就可以了!
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+1;
typedef long long LL;
int n,k;
int vis[N];
int ans=0;
int main()
{
 ios::sync_with_stdio(false);//什么意思呢?先跳过
 int x;//s1 区间最小,s2区间最大
 cin>>n>>k;
 for(int i=1;i<=n;i++)
 {
     cin>>x;
     vis[x]++;
 }
 int num=0,tmp=0;
 for(int i=100000;i>=1;i--)
 {
     if (vis[i]!=0)
     {
        num+=vis[i];
         ans+=vis[i]*i;
         tmp=i;
     }
     if (num>=k) break;
 }
 if (num==k)  cout<<ans<<endl;
 else
 {
    ans-=tmp*(num-k);
    cout<<ans<<endl;
}
    return 0;
}
  • 附 std::ios::sync_with_stdio(false);

cin速度慢,默认的时候,cin与stdin总是保持同步的,也就是说这两种方法可以混用,而不必担心文件指针混乱,同时cout和stdout也一样,两者混用不会输出顺序错乱。正因为这个兼容性的特性,导致cin有许多额外的开销,如何禁用这个特性呢?只需一个语句std::ios::sync_with_stdio(false);,这样就可以取消cin于stdin的同步了。可以理解为一个加速的外挂。

下一节 acm新手小白必看系列之(3)——暴力枚举精讲及例题

发布了8 篇原创文章 · 获赞 73 · 访问量 4777

猜你喜欢

转载自blog.csdn.net/qq_45899321/article/details/103808428