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,0001≤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") 

直接放头文件之前,可一定程度上加快程序运行(可只用几行,但比赛一般不让用)

 

 

 

 

 

 

 

 

 

 

好了,到这里本蒟蒻的常用排序就结束了

若有不足请大家指出

若有疑问可留言,尽量早回复

 

posted @ 2020-10-10 15:49  天南星魔芋  阅读(552)  评论(1编辑  收藏  举报