zoukankan      html  css  js  c++  java
  • 常用排序算法总结

    常用排序算法总结:

    稳定性作用:

        1.通常对只有一个key的记录来排序时,若两个记录的key相同,稳定排序不会改变排序前
          后的顺序。 
        2.对有多个key来说,如基数排序,从次要key开始排序,在次要key排序完成后,a1排在
          a2前,而a1和a2优先级大的key相同,当优先级大的key排序完成后a1会仍在a2前,保
          持了稳定性。
    

    稳定性排序的意义:

        1.用于多个key的排序,如基数排序这样。
        2.用于单个key的排序,如果key相同就不要改变它们的次序:
          比如你要给一个结构体排序,要求按a的大小排序,a相同的话,按输入顺序输出。
             a=4 b=100,a=1,b=200,a=4,b=300,a=5,b=400
          你如果冒泡的话(所有的稳定排序都行),会输出
             a=1 b=200,a=4 b=100,a=4 b=300,a=5 b=400
          但如果快排的话很可能输出
             a=1 b=200,a=4 b=300,a=4 b=100,a=5 b=400
          在解决某些问题时,你会发再用不稳定排序是做不到的。
    

    插入排序

    a.直接插入排序:
    #include <iostream.h>
    void InsertSort(int seq[],int len){
    
        int tem; //辅助空间tem,o(1)
    
        for(int i=1;i<len;i++)      //从第二个开始找
            if(seq[i]<seq[i-1]){    //如果小于前一个      
    
                tem = seq[i];       //提取出来
                seq[i] = seq[i-1];  //先后移一格 
    
                for(int j=i-2;j>=0&&tem<seq[j];j--)//从前两个开始往前找,直到大于等于时停止
                    seq[j+1] = seq[j];  //边找边后移
                seq[j+1] = tem;             //放入正确位置
    
            }
    }
    
    void main() {
    
        int len = 8;
        int seq_test[] = {5,9,8,10,30,1,45,34};
    
        InsertSort(seq_test,len);
    
        for(int i=0;i<len;i++)
        cout<<seq_test[i]<<endl;
    }
    b.Shell排序:
    //shell就是用的直接插入思路,只是多加一个增量dk,dk=1时就是直接插入排序(基本有序思想)
    void ShellSort(int seq[],int len,int dk){
        int tem;
    
        for(int i=dk;i<len;i++)
            if(seq[i]<seq[i-dk]){
    
                tem = seq[i];
                seq[i] = seq[i-dk];
                for(int j=i-2*dk;j>=0&&tem<seq[j];j-=dk)
                    seq[j+dk] = seq[j];
                seq[j+dk] = tem;
            }
    }

    选择排序

    a.简单选择排序:
    void SelectSort(int seq[],int len){
        int tem,k;      //K为最小值的下标
        for(int i=0;i<len-1;i++){   //总共进行len-1次排序
            k = i;
            for(int j=i+1;j<len;j++)
                if(seq[j]<seq[k])
                    k = j;
            if(k!=i){
                tem = seq[i];
                seq[i] = seq[k];
                seq[k] = tem;
            }
        }
    }
    b.堆排序(完全二叉树):
    void HeapAdjust(int seq[],int left,int right){   //左边界,右边界
        int head;       
        head = seq[left];            //要排序的头结点 
        for(int i=left*2;i<=right;i*=2){      //i当作上指针,left当作下指针
            if(i<right&&seq[i]<seq[i+1]) i++;
            if(head>=seq[i]) break;
            seq[left] = seq[i];
            left = i;
        }
    
        seq[left] = head;
    }
    
    void HeapSort(int seq[],int len){
        int tem,i;
        for(i=len/2;i>0;i--)      //将无序二叉树调整为大顶堆
            HeapAdjust(seq,i,len);    
        for(i=len;i>1;i--){       //边排列边调整
            tem = seq[1];
            seq[1] = seq[i];
            seq[i] = tem;
    
            HeapAdjust(seq,1,i-1);    
        }
    }

    交换排序

    a.冒泡排序:
    void BubbleSort(int seq[],int len){
    
        int tem;
    
        for(int i=0;i<len-1;i++)  //排序要走的趟次,满足len-1趟即可
            for(int j=0;j<len-1-i;j++)//排序范围,起始0~len-1,且每次减1
                if(seq[j]>seq[j+1]){
                    tem = seq[j];
                    seq[j] = seq[j+1];
                    seq[j+1] = tem;
                }
    }
    
    也许你会问:为什么冒泡排序最好情况下时间复杂度为o(n)?因为还可以这样来改进:
    
    void BubbleSort2(int seq[],int len){
    
        int tem;
        int FLAG;           //增加一位标志
    
        for(int i=0;i<len-1;i++){
            FLAG = 0;       //每趟初始为0
            for(int j=0;j<len-1-i;j++)
                if(seq[j]>seq[j+1]){
                    tem = seq[j];
                    seq[j] = seq[j+1];
                    seq[j+1] = tem;
                    FLAG = 1;  //交换过说明序列无序,置为1
                }
            if(!FLAG)          //为0说明已经排序完成,直接返回
                return;
        }
    }
    b.快速排序:
    int Partition(int seq[],int low,int high){      //一次划分排序
    
        int pivotkey = seq[low];     //取最低位为轴点
    
        while(low<high){             //循环直到low high相遇
            while(low<high&&seq[high]>=pivotkey) high--;     //首先从最高点开始找
            seq[low] = seq[high];
            while(low<high&&seq[low]<=pivotkey) low++;
            seq[high] = seq[low];
        }
        seq[low] = pivotkey;     //最终位置,此时low=high
        return low;              //返回划分界点
    }
    
    void QuickSort(int seq[],int low,int high){     //递归直到low=high时结束排序
    
        int pivotloc;    //划分界点位置
    
        if(low<high){
            pivotloc = Partition(seq,low,high);
            QuickSort(seq,low,pivotloc-1);
            QuickSort(seq,pivotloc+1,high);
        }
    }

    其它:

    1.用得较多的3种算法:快排,堆排,归并排序(时间nlogn)

    快排:最常用的排序算法,速度通常也是最快的。 
    最坏:O(n^2) 
    空间复杂度:O(n*logn) 
    不稳定

    堆排:特别适用于数据量很大的场合(百万级数据)。因为快排和归并排序都是基于递归的,数据量很大的情况下容易发生堆栈溢出。
    空间复杂度:O (1) 
    不稳定

    归并排序:稳定 
    空间复杂度:O(n) 
    值得注意的是,它是一种稳定的排序算法。 
    与前两种排序算法不同的是,归并排序需要额外的数组开销。

  • 相关阅读:
    深刻理解Docker镜像大小
    UVA 12657 Boxes in a Line
    STL 之 iterator traits 备忘
    python设计模式 之 简单工厂模式
    extjs 时间范围选择的实现
    数据结构
    nodeJS npm grunt grunt-cli
    Ubuntu: GlusterFS+HBase安装教程
    ubuntu 休眠之后蓝牙鼠标无效果。
    基于sparksql调用shell脚本运行SQL
  • 原文地址:https://www.cnblogs.com/mzzcy/p/7142421.html
Copyright © 2011-2022 走看看