c++常用排序
今天打了一道排序题于是心血来潮写下这篇常用
c++排序
1.冒泡排序
2.快速排序/急速排序
3.桶排序
4.另附吸氧代码
1.冒泡排序
思想:每次找出最大/最小的数,找n次
时间复杂度:O(N*N)
优点:简单易懂,不易打错
缺点:时间复杂度太高
算法模板
l[100],n;
1.maxn标记法
2.最优比较法
1.maxn标记法 降序(最大的在前) int maxn=0,jl;//maxn记录最大数,jl /*jilu记录*/ 记录maxn的j值,也就是位置 for(int i=1;i<=n;i++){ maxn=0; for(int j=i;j<=n;j++){ if(maxn<l[j])maxn=l[j],jl[j]; } swap(l[i],l[jl]);//c++函数 建议用 #include<bits/stdc++.h> }
升序(最大的在后)
int maxn=0,jl;//maxn记录最大数,jl /*jilu记录*/ 记录maxn的j值,也就是位置
for(int i=n;i>0;i--){
maxn=0;
for(int j=1;j<=i;j++){
if(maxn<l[j])maxn=l[j],jl[j];
}
swap(l[i],l[jl]);//c++函数 建议用 #include<bits/stdc++.h>
}
2.最优比较法
即每次找出一个最值
降序(最大的在前)
for(int i=1;i<=n;i++){
for(int j=1;j<=n-i;j++){
if(l[j]<l[j+1])swap(l[j],l[j+1]);//从第一个起,每次找一个最小的放最后
}
}
升序(最大的在后)
for(int i=1;i<=n;i++){
for(int j=1;j<=n-i;j++){
if(l[j]>l[j+1])swap(l[i],l[j]);//从第一个起,每次比较选一个最大的放最后
}
}
举个例子
题目描述 输出10个数,将其从小到大排序。 输入 一行,10个整数。 输出 一行,10个整数,从小到大排序。 样例输入 Copy 11 4 55 6 77 8 9 0 7 1 样例输出 Copy 0 1 4 6 7 8 9 11 55 77
对于此题 题中已明显给出n=10;
故数组 L 至少要开11(题解中解释)
然后直接套模板
#include<bits/stdc++.h> using namespace std; int n,l[15];//数组开大点,因为 L[10]只有 L[0]~L[9] 共十个 int main() { n=10; for(int i=1;i<=n;i++){ cin>>l[i]; } for(int i=1;i<=n;i++){ for(int j=1;j<=n-i;j++){ if(l[j]>l[j+1])swap(l[j],l[j+1]); } } for(int i=1;i<=n;i++) cout<<l[i]<<" "; cout<<endl; }
常见问题
1.模板多样性
降序
可以每次求最大放数组首
也可每次求最小放数组尾
反之,升序亦然
2.循环范围
第一层循环为1~n
第二层范围是什么?
1.可为1~n,因为虽然多跑了一点,但不影响判断(反正多的一部分也判断过,再次循环时不会用 swap)
2.可为1~n-i或i~n,如题解,可省时间,但要看情况(1~n-i是将每次选出的数放在数组尾,i~n则放数组开头)
2.快速排序/急速排序
思想:利用二分查找思想,每次将 L 分成两部分,保证左边的比右边的小/大,排序log2 N次
时间复杂度:O(N*log2 N)2为底数
优点:时间复杂度低,速度快,可操作性好(排序+查找 排序二维数组)常规最快
缺点:难以理解,容易打错
算法模板
int n,l[100]; void kp(int le,int ri){//要用函数 int i=le,j=ri; int mid=l[(le+ri)/2];//比较点 一般为中点 while(i<=j){ while(l[i]<mid)i++;//升序与降序 区别 互相相反 此时为升序 while(l[j]>mid)j--; if(i<=j){ //当区间 l,r 为奇数时并且i=(le+ri)/2,j=(le+ri)/2; 这时无法跳出大while循环-- swap(l[i],l[j]); // i++,j--;//-------------------------------------------------------------------/令上述i>j 或 继续找 } } if(le<j)kp(le,j);//分成两个子程序排序 le==ri 时不会分裂 if(i<ri)kp(i,ri); } int main(){ ............ kp(1,n);//调用 快排 ............ }
急速排序与思想快排一样
只是 比较点为第一个点并且排序后数组存于另一个数组
这里作为思考题给大家想想
/*其实也不太常用,还是快排好*/
举个例子
题目描述 给定一个长度为n(1≤n≤6,000,000)的无序正整数序列,以及另一个数k(1≤k≤6000,000)(关于第k大的数:例如序列{1,2,3,4,5,6}中第3大的数是4。) 输入 第一行两个正整数m,n。 第二行为n个正整数。 输出 第k大的数。 样例输入 Copy 6 3 1 2 3 4 5 6 样例输出 Copy 4 提示 1≤n≤6,000,000,1≤k≤6000,000
我们知道冒泡排序要 O(N*N)
此题 N=6,000,000
故 N*N为36万亿
而计算机每秒计算1亿
所以用快排
log2 6000000大约是23
故快排只要138百万
#include<bits/stdc++.h> using namespace std; int n,k; int o[6000005]; void kp(int l,int r){//要用函数 int i=l,j=r; int mid=o[(l+r)/2];//比较点 一般为中点 while(i<=j){ while(o[i]>mid)i++;//降序 while(o[j]<mid)j--; if(i<=j){ //当区间 l,r 为奇数时 i=(l+r)/2,j=(l+r)/2; 这时无法跳出大while循环-- swap(o[i],o[j]); // i++,j--;//------------------------------------------------------------/令上述i>j 或 继续找 } } if(l<j)kp(l,j);//分成两个子程序排序 l==r 时不会分裂 if(i<r)kp(i,r); } int main(){ cin>>n>>k; for(int i=1;i<=n;i++) scanf("%d",&o[i]); kp(1,n); cout<<o[k]<<endl; }
常见问题
1.关于模板,快排不好改,最好严格打模板
2.灵活性在if中和分裂时体现(加条件)
3.桶排序
思想:以空间带时间,数组下标为此数字,数组内装此数个数,在输入时处理
时间复杂度:O(N)
优点:速度贼快,比快排还快,代码短好理解
缺点:不适用,N 可能很大
模板
int l[1000]; int m,a;//m为个数 for(int i=1;i<=m;i++) {scanf("%d",&a);l[a]++;}
举个例子
题目描述 给定一个长度为n(n<100,000,000)的无序正整数(1~n)序列,以及另一个数k(k<100,000,000)(关于第k大的数:例如序列{1,2,3,4,5,6}中第3大的数是4。) 输入 第一行两个正整数m,n。 第二行为n个正整数。 输出 第k大的数。 样例输入 Copy 6 3 1 2 3 4 5 6 样例输出 Copy 4 提示 n<100,000,000,k<100,000,000
这次n<100,000,000了
故不能用快排了
只能用桶排 O(N)
#include<bits/stdc++.h> using namespace std; int n,k; int o[100000001]; int main(){ int a,maxn=0; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a); o[a]++; } int top=100000001; while(k>0){ top--; k-=o[top]; if(top<=0)break; } cout<<top; }
常见问题
暂未发现
4.吸氧
#pragma GCC optimize(1) #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops") #pragma GCC optimize("-falign-jumps") #pragma GCC optimize("-falign-loops") #pragma GCC optimize("-falign-labels") #pragma GCC optimize("-fdevirtualize") #pragma GCC optimize("-fcaller-saves") #pragma GCC optimize("-fcrossjumping") #pragma GCC optimize("-fthread-jumps") #pragma GCC optimize("-funroll-loops") #pragma GCC optimize("-fwhole-program") #pragma GCC optimize("-freorder-blocks") #pragma GCC optimize("-fschedule-insns") #pragma GCC optimize("inline-functions") #pragma GCC optimize("-ftree-tail-merge") #pragma GCC optimize("-fschedule-insns2") #pragma GCC optimize("-fstrict-aliasing") #pragma GCC optimize("-fstrict-overflow") #pragma GCC optimize("-falign-functions") #pragma GCC optimize("-fcse-skip-blocks") #pragma GCC optimize("-fcse-follow-jumps") #pragma GCC optimize("-fsched-interblock") #pragma GCC optimize("-fpartial-inlining") #pragma GCC optimize("no-stack-protector") #pragma GCC optimize("-freorder-functions") #pragma GCC optimize("-findirect-inlining") #pragma GCC optimize("-fhoist-adjacent-loads") #pragma GCC optimize("-frerun-cse-after-loop") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") #pragma GCC optimize("-ftree-switch-conversion") #pragma GCC optimize("-foptimize-sibling-calls") #pragma GCC optimize("-fexpensive-optimizations") #pragma GCC optimize("-funsafe-loop-optimizations") #pragma GCC optimize("inline-functions-called-once") #pragma GCC optimize("-fdelete-null-pointer-checks")
直接放头文件之前,可一定程度上加快程序运行(可只用几行,但比赛一般不让用)
好了,到这里本蒟蒻的常用排序就结束了
若有不足请大家指出
若有疑问可留言,尽量早回复