排序算法大总结

这篇博客用C++实现各种排序算法,并对他们的时间复杂度以及稳定性进行分析。
所谓稳定性是指排序前后,两个相等的数的相对位置不变。
稳定排序法:冒泡排序(交换只发生在相邻的两个不等数之间),插入排序(只跟比它大的数据交换),归并排序(我们可以规定元素相等时,先放前一序列的元素)。

不稳定排序法:堆排序,选择排序(举例:序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了),快速排序(同理,中枢元素交换时会打乱相等元素的先后顺序)。
堆排序为什么破坏稳定性:堆的结构是节点i的孩子为2i和2i+1节点,大顶堆要求父节点大于等于其2个子节点,小顶堆要求父节点小于等于其2个子节点,是完全二叉树;在一个长为n 的序列,堆排序的过程是从第n/2开始和其子节点共3个值选择最大(大顶堆)或者最小(小顶堆),这3个元素之间的选择当然不会破坏稳定性。但当为n /2-1, n/2-2, …1这些个父节点选择元素时,就会破坏稳定性。有可能第n/2个父节点交换把后面一个元素交换过去了,而第n/2-1个父节点把后面一个相同的元素没 有交换,那么这2个相同的元素之间的稳定性就被破坏了;

不稳定排序法:

  1. 冒泡排序
    template<typename T>
    bool asc(T a,T b){//升序
        return a>b;
    }
    
    template<typename T>
    bool desc(T a,T b){//降序
        return a<b;
    }
    
    template<typename T>
    void bubblesort(T *a, int n, bool(*cmpfunc)(T, T) = asc){//设置默认为升序排序
        bool sorted=false;
        T tmp;
        while(!sorted){
            sorted=true;
            for(int i=0;i<n-1;++i){
                if(cmpfunc(a[i],a[i+1])){
                    tmp=a[i];
                    a[i]=a[i+1];
                    a[i+1]=tmp;
                    sorted=false;
                }
            }
            --n;//每次for循环都会把最大或者最小的数沉到底部,这也就少排一个数
        }
    }

     

  2. 插入排序
    #include <iostream>
    using namespace std;
    
    template<typename T>
    bool asc(T a,T b){//升序
        return a>b;
    }
    
    template<typename T>
    bool desc(T a,T b){//降序
        return a<b;
    }
    
    template<typename T>
    void insertsort(T *a, int n, bool(*cmpfunc)(T, T) = asc){//设置默认为升序排序
        T tmp;
        for(int k=0;k<n-1;++k){
            int i=k+1;
            while(i>0 && cmpfunc(a[i],a[i-1])){
                tmp=a[i];
                a[i]=a[i-1];
                a[i-1]=tmp;
                --i;
            }
        }
    }
    
    //对函数进行调用
    int main()
    {
        int a[8] = {5,2,5,7,1,-3,99,56};
        int b[8] = {5,2,5,7,1,-3,99,56};
    
        insertsort<int>(a, 8);//将函数名作为指针传递过去就行
    
        for (auto e:a) std::cout << e << " ";
        std::cout << std::endl;
    
        insertsort<int>(b, 8, desc);
    
        for (auto e:b) std::cout << e << " ";
    
        return 0;
    }

     

  3. 归并排序
     
  4. 选择排序
    #include <iostream>
    using namespace std;
    
    template<typename T>
    int asc(T *a,int lo,int hi){//升序
        int idx=lo;
        T _min=a[lo];
        for(int i=lo+1;i<=hi;++i){
           if(a[i]<_min){
               _min=a[i];
               idx=i;
           }
        }
        return idx;
    }
    
    template<typename T>
    int desc(T *a, int lo,int hi){//降序
        int idx=lo;
        T _max=a[lo];
        for(int i=lo+1;i<=hi;++i){
            if(a[i]>_max){
                _max=a[i];
                idx=i;
            }
        }
        return idx;
    }
    
    template<typename T>
    void selectsort(T *a, int n, int(*cmpfunc)(T *,int,int) = asc){//设置默认为升序排序
        T tmp;
        for(int k=0;k<n;++k){
            int idx=cmpfunc(a,k,n-1);
            if(idx!=k){
                tmp=a[k];
                a[k]=a[idx];
                a[idx]=tmp;
            }
        }
    }
    
    //对函数进行调用
    int main()
    {
        int a[8] = {5,2,5,7,1,-3,99,56};
        int b[8] = {5,2,5,7,1,-3,99,56};
    
        selectsort<int>(a, 8);//将函数名作为指针传递过去就行
    
        for (auto e:a) std::cout << e << " ";
        std::cout << std::endl;
    
        selectsort<int>(b, 8, desc);
    
        for (auto e:b) std::cout << e << " ";
    
        return 0;
    }

    输出结果:
    -3 1 2 5 5 7 56 99
    99 56 7 5 5 2 1 -3

  5. 快速排序
    #include <iostream>
    using namespace std;
    
    template <typename T>
    void _swap(T &a,T &b){
        T tmp=a;
        a=b;
        b=tmp;
    }
    
    template <typename T>
    int partition(T *a,int lo,int hi){
        _swap(a[lo],a[lo+rand()%(hi-lo+1)]);
        T pivot=a[lo];
        int mi=lo;
        for(int k=lo+1;k<=hi;++k){
            if(a[k]<pivot){
                _swap(a[k],a[++mi]);
            }
        }
        swap(a[lo],a[mi]);
        return mi;
    }
    
    template<typename T>
    void quicksort(T *a, int lo, int hi){//设置默认为升序排序
        if(hi<=lo)
            return;
        int mid=partition(a,lo,hi);
        quicksort(a,lo,mid-1);
        quicksort(a,mid+1,hi);
    }
    
    //对函数进行调用
    int main()
    {
        int a[8] = {5,2,5,7,1,-3,99,56};
        int b[8] = {5,2,5,7,1,-3,99,56};
    
        quicksort<int>(a, 0,7);//将函数名作为指针传递过去就行
    
        for (auto e:a) std::cout << e << " ";
        std::cout << std::endl;
    
        quicksort<int>(b, 0,7);
    
        for (auto e:b) std::cout << e << " ";
    
        return 0;
    }

     

  6. 堆排序
     

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值