本人发的第一篇啦,第一次写不足之处多多见谅。
前几天练stl排序算法,感觉还不错欸~~
题单索引:【算法1-2】排序 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/training/107#information
一,基本应用(咋排序啊)
1.sort函数类:
头文件:
#include<algorithm>
(1)sort:
sort(first,last,comp)
对[first, last)范围内的元素按comp规则进行排序。
注意:排序的范围[first, last),包括first,不包括last。
对于comp:
less:小于,默认值,可不写,升序排序
greater:大于,降序排序
less_equal:小于等于
greater_equal:大于等于
也可以自定义比较函数。
举个例子:
#include<bits/stdc++.h>
using namespace std;
bool my_less(int i, int j) {return (i< j);}//自定义小于
bool my_greater(int i, int j) {return (i> j);}//自定义大于
int main ()
{
int a[]={1,3,8,2,6,2,5,4};
sort(a+2,a+6); //对4个数排序,结果:1 3 2 2 6 8 5 4
sort(a,a+8,less<int>()); //结果:1 2 2 3 4 5 6 8
sort(a,a+8,my_less); //自定义排序,结果:1 2 2 3 4 5 6 8
sort(a,a+8,greater<int>());//从大到小排序,结果:8 6 5 4 3 2 2 1
sort(a,a+8,my_greater); //结果:8 6 5 4 3 2 2 1
stable_sort(a+3,a+8); //结果:8 6 5 1 2 2 3 4
return 0;
}
luogu提供了模板题呢:
P1177: P1177 【模板】排序 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int main()
{
vector<int> a;
int n,i;
cin>>n;
for(i=0;i<n;i++)
{
int x;
cin>>x;
a.push_back(x);
}
sort(a.begin(),a.end());
for(i=0;i<n;i++)
cout<<a[i]<<" ";
return 0;
}
简单的哒~
(2)stable_sort
stable_sort(first, last, comp)
stable在字面意思上讲就是稳定哒!qwq
和sort()相似,不同之处在于,对于[first, last) 范围内值相同的元素,不会改变它们的相对位置(保持原输入顺序)。
比如说:
4 2 6 3 5 2 1(红色为第一个2,蓝色为第二个2)
1 2 2 3 4 5 6
(3)partial_sort
partial_sort(first, middle, last, comp)
是部分嘛~~
以交换元素存储位置的方式实现部分排序,将[first, last) 范围内最小(或最大)的 middle-first 个元素移动到 [first, middle) 区域中,并对这部分元素做升序(或降序)排序。
比如说:partial_sort(a,a+3,a+7);
4 2 6 3 5 7 1
1 2 3 6 5 7 4
(4)nth_element
nth_element(first, nth, last, comp)
采用默认的升序时,该函数从某个序列中找到第k小的元素e(序列下标从0开始),并将e移动到序列中第k的位置处(默认是求区间第k小的)。而且,整个序列经过nth_element()函数处理后,所有位于e之前的元素都比e小,所有位于e之后的元素都比e大。
比如说:nth_element(a,a+k,a+n)
把下标为k的元素放在正确位置,对其它元素并没有排序,且k左边元素都小于等于它,右边元素都大于等于它,因此可利用这个函数快速定位某个元素。
比如说:nth_element(a,a+n-k,a+n)
将下标为n-k,也就是第n-k+1个数放在正确的位置,求的是第k大的数a[n-k]。
luogu有呢:
P1923 :P1923 【深基9.例4】求第 k 小的数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
第一次做时看这个题不让用nth_element,这是啥啊 ??? *-*
既然学到了就看看咋用呗,先学会了再手搓原理。。。
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
vector<int> e;
for(int i=0;i<n;i++)
{
int f;
cin>>f;
e.push_back(f);
}
nth_element(e.begin(),e.begin()+m,e.end());
printf("%d",e[m]);
return 0;
}
(5)is_sorted
is_sorted(first, last, comp)
用的不多呐。。。
检测 [first, last) 范围内是否已经排好序,默认检测是否按升序排序。
判断一下:
#include<bits/stdc++.h>
using namespace std;
int main ()
{
int b[]={3,7,2,5,6,8,5,4};
partial_sort(b,b+3,b+8); //结果:2 3 4 7 6 8 5 5
partial_sort(b,b+3,b+8,greater<int>()); //结果:8 7 6 2 3 4 5 5
if (is_sorted(b,b+3,greater<int>()))
cout<<"is sorted"<<endl; //输出:is sorted
//排动态数组:
vector<int> c = {1,2,3,4,5,6,7,8};//C11
sort(c.begin(),c.end(),my_greater); //结果:8 7 6 5 4 3 2 1
//排字符串
string s="hello world";
sort(s.begin(),s.end(),greater<char>());
cout<<s<<endl;//输出: wroolllhed注意最后一个是空格
return 0;
}
2.set函数类:
头文件:
#include<set>
set就是集合,STL的set用二叉树实现,集合中的每个元素只出现一次(参照数学中集合的互斥性),并且是排好序的(默认按键值升序排列)。
也就是说,这玩意儿又能去重又能排序嘿嘿~~
附上链接:c++ set用法详解-CSDN博客
3.优先队列:
头文件:
#include<queue>
可以做到一边插入一边排序,挺快的。(写过用sort超时但优先队列不超时的程序,呜呜哭死)
懒得讲了。。看大佬代码偷学会的,可以看看其他大佬的博客。
附上链接:【原创】优先队列 priority_queue 详解-CSDN博客
二,刷luogu(🤮)
不就是个排序嘛,有啥难的。。。
P1271:P1271 【深基9.例1】选举学生会 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
简简单单的排序应用,学生会定律对吧。。。
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int a[2000000],n,m,i;
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
scanf("%d",&a[i]);
sort(a,a+m);
for(i=0;i<m;i++)
printf("%d ",a[i]);
return 0;
}
P1059:P1059 [NOIP2006 普及组] 明明的随机数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
嗨嗨嗨,这不set超简单嘛~
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
set<int> e;
int n;
cin>>n;
for(int i=0;i<n;i++)
{
int a;
cin>>a;
e.insert(a);//插入元素
}
int l=e.size();
printf("%d\n",l);//去重了,输出个数
for(auto it:e)
{
printf("%d ",it);//输出
}
return 0;
}
P1093:P1093 [NOIP2007 普及组] 奖学金 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
用优先队列写的,记得一定看好排序规则哈~~(有个样例终于改对了呜呜)。。。
其实也不用这么麻烦🙂。。。
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
struct stud{
int id;
int ch;
int ma;
int en;
int sum;
friend bool operator<(stud a,stud b)
{
if(a.sum==b.sum)
{
if(a.ch==b.ch)
return a.id>b.id;
else
return a.ch<=b.ch;
}
return a.sum<=b.sum;
}
};
priority_queue<stud> e;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
for(int i=0;i<n;i++)
{
int a,b,c;
cin>>a>>b>>c;
e.push({i+1,a,b,c,a+b+c});
}
int cn=0;
while(!e.empty())
{
stud it=e.top();
cout<<it.id<<" "<<it.sum<<endl;
cn++;
if(cn==5)
break;
e.pop();
}
return 0;
}
P1781:P1781 宇宙总统 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
哦~我亲爱的孩子,为啥不是牢大?(我没意见)
注意一下这个字符串型的数字如何判断大小,我记得当初从高精度减法偷学的。。。
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
struct stud{
string s;
int id;
friend bool operator <(stud a,stud b)
{
return a.s.size()<b.s.size()||a.s.size()==b.s.size()&&a.s<b.s;
}
};
int main()
{
ios::sync_with_stdio(0);
priority_queue<stud> e;
cin.tie(0);
cout.tie(0);
int n;
cin>>n;cin.ignore();
for(int i=0;i<n;i++)
{
string ss;
cin>>ss;
e.push({ss,i+1});
}
auto it=e.top();
cout<<it.id<<endl<<it.s;
return 0;
}
P2676:P2676 [USACO07DEC] Bookshelf B - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
入门题,注意降序排列(也可以升序排则倒着找)。
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
vector<int> s(n+10,0);
for(int i=0;i<n;i++)
cin>>s[i];
sort(s.begin(),s.end(),greater<int>());
int sum=0,cn=0;
for(int i=0;i<n;i++)
{
sum+=s[i];
cn++;
if(sum>m)
break;
}
cout<<cn;
return 0;
}
P1116:P1116 车厢重组 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
冒泡排序呢。
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
int sum;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
vector<int> s(n+10,0);
for(int i=0;i<n;i++)
cin>>s[i];
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n;j++)
if(s[i]>s[j])
{
sum++;
swap(s[i],s[j]);
}
cout<<sum;
return 0;
}
P1152:P1152 欢乐的跳 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
暴力找,然后排序呗,最后判断过程记得剪枝。
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
vector<int> s(n+10,0),v;
for(int i=0;i<n;i++)
cin>>s[i];
for(int i=1;i<n;i++)
v.push_back(abs(s[i]-s[i-1]));
sort(v.begin(),v.end());
for(int i=0;i<v.size();i++)
{
if(v[i]!=i+1)
{
printf("Not jolly\n");
return 0;
}//判断输出
}
printf("Jolly\n");//如果未能输出,则为正确答案
return 0;//过程结束
}
P1068:P1068 [NOIP2009 普及组] 分数线划定 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
优先队列写累了,这次结构体排序写法。。。
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
struct stud
{
string id;
int gra;
}stu[100001];
bool cmp(struct stud a,struct stud b)
{
if(a.gra==b.gra)
return a.id<b.id;
return a.gra>b.gra;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin.ignore();
cin>>stu[i].id>>stu[i].gra;
}
sort(stu,stu+n,cmp);//排序
int line=m*1.5;//找出分数线
cout<<stu[line-1].gra<<" ";
int cn=0;
for(int i=0;i<n;i++)
{
if(stu[i].gra>=stu[line-1].gra)
cn++;
else
break;
}//记录个数
cout<<cn<<endl;
for(int i=0;i<cn;i++)
cout<<stu[i].id<<" "<<stu[i].gra<<endl;
return 0;
}
P5143:P5143 攀爬者 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这不就是计算题,乐~(义务教育上个寂寞qwq)
坐标中直线距离算出来相加哈。。。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
struct dir
{
int x,y,z;
}a[50001];
bool cmp(struct dir x,struct dir y)
{
return x.z<y.z;
}
int n;
double ans;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i].x>>a[i].y>>a[i].z;
sort(a+1,a+n+1,cmp);
for(int i=2;i<=n;i++)
ans+=sqrt((a[i-1].x-a[i].x)*(a[i-1].x-a[i].x)+(a[i-1].y-a[i].y)*(a[i-1].y-a[i].y)+(a[i-1].z-a[i].z)*(a[i-1].z-a[i].z));//题意给的公式,sqrt是开根号
printf("%.3lf",ans);
return 0;
}
P1104:P1104 生日 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
啥时候给我生日礼物(滑稽doge)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<iostream>
using namespace std;
struct birthday
{
string name;
int year,mon,day,id;
friend bool operator <(struct birthday x,struct birthday y)
{
if(x.year==y.year)
{
if(x.mon==y.mon)
{
if(x.day==y.day)
return x.id<y.id;
return x.day>y.day;
}
return x.mon>y.mon;
}
return x.year>y.year;
}
};
int main()
{
int n;
cin>>n;
cin.ignore();
priority_queue<birthday> e;
for(int i=0;i<n;i++)
{
string ss;
int a,b,c;
cin>>ss>>a>>b>>c;
e.push({ss,a,b,c,i});
}
while(!e.empty())
{
cout<<e.top().name<<endl;
e.pop();
}
return 0;
}
P1012:P1012 [NOIP1998 提高组] 拼数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这题有点不好想啊,为贪心思想
对贪心正确性的证明:
分析可见两同样长字符串a和b,若a比b大,必有x使得 a在x位第一次b大 。
说明前面的位大,就可以忽略后面的位,可以贪心解决,把对字典序贡献最大的放在前面。比较方法只要比较 a+b和b+a的大小即可。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<iostream>
using namespace std;
bool cmp(string s1,string s2)
{
return s1+s2>s2+s1;
}
int main()
{
int n;
string s[2000];
cin>>n;
for(int i=0;i<n;i++)
cin>>s[i];
sort(s,s+n,cmp);
for(int i=0;i<n;i++)
cout<<s[i];
return 0;
}
结束辣,感谢阅读!!!!
第一次写的不好,见谅见谅呜呜。。。