zoukankan      html  css  js  c++  java
  • ❤️排序❤️

    插入排序

    插入排序

    每次将一个待排序的记录按其关键字大小'插入'到前面'已排好序的子序列中',类似于扑克牌的插入
    例如 n=6,数组R的六个排序码分别为:17,3,25,14,20,9。它的直接插入排序的执行过程
    


    void InsertSort(ElemType A[],int n){
        int i,j;
        for(i=2; i<=n; i++){
            if(A[i] < A[i-1]){
                A[0] = A[i];    //复制给哨兵,A[0]不存元素
                for(j=i-1; A[0]<A[i]; --j){
                    A[j+1] = A[j];      //向后移动
                }
                A[j+1] = A[0];      //复制到插入位置
            }
        }
    }
    

    希尔排序

    先将整个待排序的记录序列分割成为若干子序列分别进行'直接插入排序',待整个序列中的记录“基本有序”时,
    再对全体记录进行依次直接插入排序。假设增量为5,则i,i+5....;下图增量为5
    

    void ShellSort(ElemType A[],int n){
        //A[0]用来暂存单元
        for(i=dk+1; dk>=1; dk=dk/2){    //步长变化
            for(i=id+1; i<=n; i++){
                if(A[i] < A[i-dk]){     //需将A[i]插入有序增量表
                    A[0] = A[i];        //暂存在A[0]
                    for(j=i-dk; j>0&&A[0]<A[j]; j-=dk){
                        //记录后移,查找插入的位置
                        A[j+dk] = A[j];     
                    }
                    A[j+dk] = A[0]      //插入
                }
            }
        }
    }
    

    交换排序

    冒泡排序

    对待排序序列从后向前(从下标较大的元素开始),'依次比较相邻元素'的排序码,若发现'逆序则交换',
    使排序码较小的元素逐渐从后部移向前部,就象水底下的气泡一样逐渐向上冒。
    例如,n=6,数组R的六个排序码分别为:17,3,25,14,20,9。下面图给出冒泡排序算法的执行过程。
    

    void BubbleSort(ElemType A[],int n){
        for(i=0; i<n-1; i++){
            flag = false;   //表示本趟冒泡是否发生交换
            for(j=n-1; j<i; j--){   //一趟冒泡过程
                if(A[j-1] > A[j]){
                    swap(A[j-1],A[i]);  //交换
                    flag = true;
                }
                if(flag == false){
                     //表示遍历后没有发生交换,说明表已有序
                    return;    
                }
            }
        }
    }
    

    快速排序

    基本思想是:取待排序序列中的某个元素(一般第一个元素)作为基准,通过一趟排序,将待排元素分为'左右两个子序列',
    '左子序列元素'的排序码均'小于或等于基准元素'的排序码,
    '右子序列'的排序码则'大于基准元素'的排序码,
    然后分别对两个子序列继续进行快速排序,直至整个序列有序。
    元素的比较和交换是从两端向中间进行的,排序码较大的元素一次就能够交换到后面,排序码较小的记录一次就能够交换到前面,
    记录每次移动的距离较远,因而总的比较和移动次数较少。
    例如,给定排序码为:'(46,55,13,42,94,05,17,70)'
    

    一次划分

    void QuickSort(ElemType A[],int low,int high){
        if(low < high){
            /*
            Partition()就是划分操作,将A[low....high]
            划分为满族上述条件的两个子表
            */
           int pivotpos = Partition(A,low,high);    //划分
           QuickSort(A,low,pivotpos-1);    //依次对两个子表进行递归排序
           QuickSort(A,pivotpos+1,high);    
        }
    }
    
    int Partition(ElemType A[],int low,int high){
        //一次划分
        ElemType pivot = A[low];    //将当前表中第一个元素设为轴,对表进行划分
        while(low < high){
            while(low<high && A[low]>=pivot){
                --high;
            }
            A[low] = A[high];   //将比轴小的元素移动到左端
            while(low<high && A[low]<=pivot){
                ++low;
            }
            A[high] = A[low];   //将比轴大的元素移动到右端
        }
        A[low] = pivot; //将轴元素放到最终位置
        return low;     //返回存放轴饿最终位置
    }
    

    选择排序

    简单选择排序

    基本思想是:第一次从'array[0]~array[n-1]'中'选取最小值',与'array[0]'交换,
    第二次从'array[1]~array[n-1]'中选取最小值,与'array[1]'交换,
    第三次从'array[2]~array[n-1]'中选取最小值,与'array[2]'交换,…
    例如,给定n=8,数组R中的8个元素的排序码为:'(8,3,2,1,7,4,6,5)'
    

    void SelectSort(ElemType A[],int n){
        for(i=0; i<n-1; i++){
            //一共进行n-1趟
            min = i;    //记录最小元素位置
            for(j=i+1; j<n; j++){   //找最小元素
                if(A[j] < A[min]){
                    min = j;    //更新最小元素的位置
                }
                if(min != j){
                    swap(A[i],A[min]);  //交换
                }
            }
        }
    }
    

    堆排序

    将排序码k1,k2,k3,…,kn表示成'一棵完全二叉树',然后从第n/ 个排序码(即树的最后一个非叶结点)开始筛选,
    使由该结点作根结点组成的子二叉树符合堆的定义,然后从第n/2 -1个排序码重复刚才操作,直到第一个排序码止。
    这时候,该二叉树符合堆的定义,初始堆已经建立。 
    可以按如下方法进行堆排序:将堆中第一个结点(二叉树根结点)和最后一个结点的数据进行交换(k1与kn),
    再将k1~kn-1重新建堆,然后k1和kn-1交换,再将k1~kn-2重新建堆,然后k1和kn-2交换,如此重复下去,
    每次重新建堆的元素个数不断减1,直到重新建堆的元素个数仅剩一个为止。
    

    void BuildMaxHeap(ElemType A[],int len){
        for(i=len/2; i>0; i--){     //从i=[n/2]~1,反复调整堆
            HeadAdjust(A,i,len);    
        }
    }
    
    void HeadAdjust(ElemType A[],int k,int len){
        A[0] = A[k];    //A[0]暂存子树的根节点
        for(i=2*k; i<=len; i*=2){   //沿key较大的子节点向下筛选
            if(i<len && A[i]<A[i+1]){
                i++;    //去key较大的子节点的下标
            }
            if(A[0] >= A[i])    break;  //筛选结束
            else{
                A[k] = A[i];    //将A[i]调整到双亲结点
                k = i;  //修改k值,以便继续向下筛选
            }
        }
        A[k] = A[0];    //被筛选节点的值的最终位置
    }
    

    归并排序

    将两个(或两个以上)有序表合并成一个'新的有序表',即把待排序序列'分为若干个子序列',每个子序列是'有序的'。然后再把有序子序列合并为整体有序序列。
    

    //辅助数组B
    ElemType *B=(ElemType*)malloc((n+1)*sizeof(ElemType));
    
    void Merge(ElemType A[],int low,int mid,int high){
        //表A的两段A[low...mid]和A[mid+1...high]各自有序,将他们合并成一个有序表
        for(k=low; k<=high; k++){
            B[k] = A[k];    //将A中的所有元素复制到B中
        }
        for(i=low,j=mid+1,k=i; i<=mid&&j<=high; k++){
            if(B[i] <= B[j]){   //比较B的左右两段中的元素
                A[k] = B[i++];  //将较小值复制到A中
            }else{
                A[k] = B[j++];
            }   
        }
        while (i<=mid) A[k++] =B [i++]; //若第一个表未检测完,进行复制
        while (i<=mid) A[k++] =B [j++]; //若第二个表未检测完,进行复制   
    }
    
    void MergeSort(ElemType A[],int low,int high){
        if (low<high){
            int mid=(low+high)/2;   //从中间划分两个子序列
            MergeSort(A ,low,mid);  //对左子序列进行递归排序
            MergeSort(A ,mid+1,high);  //对右子序列进行递归排序
            Merge(A,low,mid,high);  //归并        
        }
    }
    

    基数排序

    数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,
    它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,
    基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
    


    各个排序比较

    '不稳定':'快选堆希'(快速排序、选择排序、堆排序、希尔排序)
    '稳定':'插冒归计基'(简单插入排序、冒泡排序、归并排序、计数排序、基数排序)
    移动次数和关键字顺序无关的排序:
    '一堆(堆排序)海龟(归并排序)选(选择排序)基(基数排序)友'--->'堆排序、归并排序、选择排序、基数排序'
    

    败者树balabala.. 不想写了 写吐了

    部分图片来自王道数据结构书中

  • 相关阅读:
    LeetCode Power of Three
    LeetCode Nim Game
    LeetCode,ugly number
    LeetCode Binary Tree Paths
    LeetCode Word Pattern
    LeetCode Bulls and Cows
    LeeCode Odd Even Linked List
    LeetCode twoSum
    549. Binary Tree Longest Consecutive Sequence II
    113. Path Sum II
  • 原文地址:https://www.cnblogs.com/xiaofff/p/13288748.html
Copyright © 2011-2022 走看看