• 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];
        }
    
  • 相关阅读:
    282. Expression Add Operators
    281. Zigzag Iterator
    280. Wiggle Sort
    How Not to Crash #2: Mutation Exceptions 可变异常
    Moving Swiftly
    How to Use updateConstraints
    Don’t Put View Code Into Your View Controller别把View创建的代码放在VC中
    Where-To-Put-The-Auto-Layout-Code
    iOS five years[转]
    ResponderChain note
  • 原文地址:https://www.cnblogs.com/codespoon/p/13234684.html
Copyright © 2020-2023  润新知