acm新手小白必看系列之(2)——排序及cmp函数
sort排序
- sort是c++自带函数 复杂度 n*log(n) 包含在头文件
#include的c++标准库里 函数有三个参数
1.要排序的数组的起始地址
2.数组的结束地址
3.第三个参数是排序的方法,可以不写,默认是从小到大 - sort(a,a+n) -----默认从小到大排序 比如 int a[ ]={2,7,1,5,0}
- 我们可以写成
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
100 有2个
99有3个
88 有4个
77有2个
66 有1个
从大到小 凑齐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)——暴力枚举精讲及例题