• 由入门到入土的排序专题


    排序

    选择排序

    //选择排序的核心思想是找到一个最小的元素(第二层循环中ji就是最小元素在无序数组中的编号)然后把它放到最前面
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int a[99999999],n;
    void swap(int &l,int &k){
        int t=l;
        l=k;
        k=t;
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            int ji=i;
            for(int j=i+1;j<=n;j++){
                if(a[j]<a[ji])ji=j;
            }
            if(ji!=i)
    //      {//或者这样也行 
    //          int t=a[i];
    //          a[i]=a[ji];
    //          a[ji]=t;
    //      }
                swap(a[i],a[ji]);//要传址调用 
        }
        cout<<endl;
        for(int i=1;i<=n;i++)
            printf("%d ",a[i]);
        return 0;
    }
    

    正版冒泡

    //冒泡排序的核心思想是一遍一遍地比较相邻两个数并交换顺序
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[99999999],n;
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=n-1;i>=1;i--){
            for(int j=0;j<=i;j++){
                if(a[j]>a[j+1]) swap(a[j],a[j+1]);
            }
        }
        for(int i=1;i<=n;i++)printf("%d ",a[i]);
        return 0;
    }
    

    盗版冒泡

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[99999999],n;
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(a[i]>a[j]) swap(a[i],a[j]);
            }
        }
        for(int i=1;i<=n;i++)printf("%d ",a[i]);
        return 0;
    }
    

    插排

    //顾名思义
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[99999999],n,i,j;
    void yi(int p,int q)
    {
        for(int h=q;h>p;h--)a[h]=a[h-1];
    }
    int main(){
        cin>>n;
        for( i=1;i<=n;i++)scanf("%d",&a[i]);
        for( i=2;i<=n;i++){//a[i]为需要插入的数 
            for( j=i-1;j>=1;j--)//寻找插入点 
                if(a[j]<a[i])break;
                if(j!=i-1){//需要将a[i]插入a[j]后 
                    int temp=a[i];
                    yi(j+1,i);
                    a[j+1]=temp;
                }
        }
        cout<<endl;
        for(i=1;i<=n;i++)printf("%d ",a[i]);
        return 0;
    }
    

    桶排

    //开一个数组记录所有数字出现了几次,最后按数组顺序输出
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[99999999],n,ji;
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&ji);
            a[ji]++;
        }
        for(int i=0;i<=n;i++){
            while(a[i]){
                printf("%d ",i);
                a[i]--;
            }
        }
        return 0;
    }
    

    快速排序

    #include<bits/stdc++.h>
    using namespace std;
    int n,a[100005];
    int read(){//快读优化
    	int x=0;char ch=getchar();
    	while(ch>'9'||ch<'0')ch=getchar();
    	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return x;
    }
    void quick_sort(int l,int r){
    	if(l>=r)return ;
    	int mid=a[(l+r)>>1],i=l,j=r;//我习惯用将基准数设为中间的那个数
    	while(i<=j){
    		while(a[i]<mid)++i;//不能加‘=’,否则当mid为整个数组中的最大数时会陷入死循环
    		while(a[j]>mid)--j; 
    		if(i<=j){//要特判,否则i>j了就是在帮倒忙了
    			swap(a[i],a[j]);
    			++i,--j;//不在原地踏步
    		}
    	}
    	if(l<j)quick_sort(l,j);//!!! 一遍快排之后i>j了所以~
    	if(r>i)quick_sort(i,r);
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;i++){
    		a[i]=read();
    	}
    	quick_sort(1,n);
    	for(int i=1;i<=n;i++){
    		cout<<a[i]<<" ";
    	}
    }
    

    三数取中+冒泡版 快排

    //
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[99999999],n;
    void cha(int p,int q){//p<q 
    	int ji=0,j;
        for(int i=p+1;i<=q;i++){
    		for(j=p;j<i;j++)if(a[i]<a[j])break;
    		ji=a[i];
    		for(int k=i-1;k>=j;k--){//千万记得是倒序赋值
    			a[k+1]=a[k];
    		}
    		a[j]=ji;
        }
    }
    void quick(int le,int ri){
        if(le>=ri)return;
        if(ri-le<=10)cha(le,ri);
        int t=(le+ri)/2,mid,x=le,y=ri;//在左端点右端点和中点位置的三个数中选取大小排中间的数,并将另外两数按大小分别赋给左右端点
        if(a[le]<a[t]){
            if(a[t]>a[ri]){
                int w=a[t];
                a[t]=a[ri];
                a[ri]=w;
            }
        }
        if(a[le]>a[t]){
            int w=a[t];
            a[t]=a[le];
            a[le]=w;//a[le]<a[t]
            if(a[t]>a[ri]){
                int w=a[t];
                a[t]=a[ri];
                a[ri]=w;
            }
        }
        mid=a[t];
        while(x<=y){
            while(a[x]<mid)x++;
            while(a[y]>mid)y--;
            if(x<=y){
                int w=a[x];
                a[x]=a[y];
                a[y]=w;
                x++;
                y--;
            }
        }
        if(le<y)quick(le,y);
        if(x<ri)quick(x,ri);
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    	quick(1,n);
        for(int i=1;i<=n;i++)printf("%d ",a[i]);
    	return 0;
    }
    

    归并排序

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[99999999],b[99999999],n;
    void gui(int le,int ri)
    {
        if(le==ri)return;
        int mid=(le+ri)/2,x=le,y=mid+1,k=le;
        gui(le,mid);
        gui(mid+1,ri);
        while(x<=mid&&y<=ri)
            if(a[x]<a[y])b[k++]=a[x++];
            else b[k++]=a[y++];
        while(x<=mid)b[k++]=a[x++];
        while(y<=ri)b[k++]=a[y++];
        for(int g=le;g<=ri;g++)a[g]=b[g];
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        gui(1,n);
        for(int i=1;i<=n;i++)printf("%d ",a[i]);
        return 0;
    }
    

    基数排序

    基数排序的核心思想是按顺序(从高往低或者从低往高)比较每个数字的个位十位百位等等,每次按当前数位上的数值大小将数组重新排列,然后将新数列按下一位上的数值大小比较并再次排序,以此类推即可得到答案
    #include<iostream>
    #define ll long long 
    using namespace std;
    ll ma,n,a[200000],tub[15][200000],bas[15]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000},k;
    int main(){
    	cin>>n;
    	for(ll i=1;i<=n;i++){
    		cin>>a[i];
    		ll t=1;
    		while(a[i]>=bas[t])++t;
    		ma=max(ma,t);//统计有多少位 
    	}
    	for(ll t=1;t<=ma;t++){
    		for(ll i=1;i<=n;i++){
    			k=(a[i]%(bas[t]))/bas[t-1];tub[k][++tub[k][0]]=a[i];//按当前位大小放入桶子里 
    		}
    		ll now=1;
    		for(ll i=1;i<=n;i++)
    			for(k=0;k<=9;k++){
    				for(ll ji=1;ji<=tub[k][0];ji++)
    					a[now++]=tub[k][ji];//按桶子的顺序重新排序 
    					tub[k][0]=0;//记录桶子里有多少个数 
    			}
    	}
    	for(ll i=1;i<=n;i++)cout<<a[i]<<" ";
    }
    

    测试数据生成器

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    using namespace std;
    int main(){
        freopen("testdata.in","w",stdout);
        srand((unsigned)time(NULL));
        for(int i=1;i<=10000;i++)
            printf("%d ",rand());
        return 0;
    }
    
    本文版权归作者LHR,欢迎转载,但未经LHR同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则LHR保留追究法律责任的权利。
  • 相关阅读:
    -1.#IND000 &&图像类型转换
    三维点集拟合:平面拟合、RANSAC、ICP算法
    深度学习:又一次推动AI梦想(Marr理论、语义鸿沟、视觉神经网络、神经形态学)
    三维重建:Kinect几何映射-SDK景深数据处理
    《SLIC Superpixels》阅读笔记
    中国企业系列
    关于抠图的一些文章方法收集
    数学空间引论
    PCL:解决PCL和OpenCV冲突的方法
    游戏开发:OpenGL入门学习
  • 原文地址:https://www.cnblogs.com/lqhsr/p/15334053.html
Copyright © 2020-2023  润新知