5.排序(下)

归并排序

  • 特点

    • 非原地,空间复杂度O(n)
    • 稳定
    • O(nlogn)
  • 归并排序的思想是如果要排序一个数组,我们先把数组从中间分为前后两部分,然后对前后部分分别排序,再将排好序的两部分合在一起,这样整个数组就都有序了

快速排序

  • 特点

    • 原地
    • 不稳定
    • O(nlongn)
  • 选择一个分区点pivot,把它放到正确的地方,这样数组被分为两部分,然后前后两部分继续此过程

桶排序

  • 核心思想:将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序,最后把每个桶里的数据按顺序取出,组成的序列就是有序的了

  • 时间复杂度:O(n)

    • 如果要排序的数据有 n 个,我们把它们均匀地划分到 m 个桶内,每个桶里就有 k=n/m 个元素

    • 每个桶内部使用快速排序,时间复杂度为 O(k * logk)。m 个桶排序的时间复杂度就是 O(m * k * logk)

    • 因为 k=n/m,所以整个桶排序的时间复杂度就是 O(n*log(n/m))

    • 当桶的个数 m 接近数据个数 n 时,log(n/m) 就是一个非常小的常量,这个时候桶排序的时间复杂度接近 O(n)

  • 桶排序比较适合用在外部排序中,数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中

  • 桶排序对数据的要求

    • 数据容易被划分为m个桶,并且桶与桶直接有着天然的顺序

    • 数据在各个桶之间分布比较均匀,在极端情况下,如果数据全都被划到一个桶里,那就退化为O(nlogn)的排序算法了

计数排序

  • 桶排序的特殊情况,当要排序的数据所处范围并不大时,我们可以把数据分为max-min+1个桶(比如高考满分750分,设置751个桶放置考生成绩),桶内存放数据出现的次数

  • 具体做法

    • 遍历原数组A,数据每出现一次,对应桶的计数+1(C[n]++)

    • 得出排序好的数据

    • 将桶内数据顺序求和(每个桶内不再是数据出现次数,而是小于等于该数据的个数)

    • 准备好一个结果数组R

    • 从后到前遍历原数组A,取出C[n],C[n]代表原数组中小于等于n的数据一共有C[n]个,那么原数据A[n]就应该放到结果数组R的C[n]处,然后将C[n]--

快排、计数Java实现

    /**
     * 快速排序
     *
     * @param arr 数组
     * @param p 要排序部分左下标
     * @param r 右下标
     */
    public static void quickSort(int arr[], int p, int r) {
        if (p >= r) return;
        //选择一个分区点(设为r)
        int pivot = arr[r];
        //将分区点放到它正确的位置
        //[p,i)为已处理区间,[j,r)为未处理区间,处理完毕后i左边全小于等于pivot,右边全大于pivot
        int i = p;
        for(int j = p; j < r ; j++){
            //将小于pivot的值放到已处理区间
            if(arr[j] < pivot){
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
                i++;
            }
        }
        //最后将pivot放在i处
        int temp = arr[i];
        arr[i] = arr[r];
        arr[r] = temp;

        //重复选择-放置过程
        quickSort(arr,p,i-1);
        quickSort(arr,i+1,r);
    }

    /**
     * 计数排序
     * @param arr
     * @param max
     */
    public static void countingSort(int arr[], int max){
        //桶C用于存储累计值
        //统计各数据出现次数
        int c[] = new int[max + 1];
        for(int i : arr)
            c[i]++;

        //得出排序好的数组
        //C中数据累计相加
        for(int i = 1; i < c.length; i++){
            c[i] += c[i - 1];
        }
        //从后往前遍历原数组 将arr[n]放置在R[c[arr[n]]]处
        int result[] = new int[arr.length];
        for(int i = arr.length - 1; i >= 0; i--){
            result[--c[arr[i]]] = arr[i];
        }
        for(int i = 0; i < arr.length; i++)
            arr[i] = result[i];
    }
posted @ 2020-07-04 13:40  codespoon  阅读(144)  评论(0编辑  收藏  举报