zoukankan      html  css  js  c++  java
  • 算法

    非基于比较的排序

    非基于比较的排序与样本的数据状况有很大的关系,由于这个限制使其在工程中并不常用。

    非基于比较的排序有桶排序,基数排序,计数排序。这三者都能做到排序的稳定性,时间复杂度为 O(n),空间复杂度为 O(n)。

    问题一 计数排序和基数排序

    假设存在一组数据,里面的数据只有 0 ~ 60 ,使用非基于比较的排序。

    思路:

    此时可以使用计数排序,准备 61 个桶并编号 0 ~ 60 (具体实现可以是一个长度为 61 的数组,也可以是其他的数据结构,桶只是一个抽象的概念),然后将数据遍历,按照数值放入对应编号的桶中。

    按次序遍历桶,如果 0 号桶存放的数字为5,则打印 5 个 0 ,最终就可以得到一个排序的数列。

    public static void bucketSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        //由于知道数据的范围,桶的大小才能确定
        int[] bucket = new int[61];
        //不知道数据的范围
        //int max = Integer.MIN_VALUE;
        //for (int i = 0; i < arr.length; i++) {
        //    max = Math.max(max, arr[i]);
    	//}
        //int[] bucket = new int[max + 1];
        for (int i = 0; i < arr.length; i++) {
            bucket[arr[i]]++;
    	}
        int arr_index = 0;
        for (int j = 0; j < bucket.length; j++) {
            while (bucket[j]-- > 0) {
                arr[arr_index++] = j;
            }
    	}
    }
    

    如果此时数据范围变得较大,如 0 ~ 1,000,000,000 ,则不宜使用计数排序,应该使用基数排序。基数排序只准备 10 个桶,分别编号 0 ~ 9,从个位开始,按照个位数的值进入桶,按照桶编号从小到大倒出数。循环,依次比较十位、百位、千位···

    问题二 使用非基于比较排序

    给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度 O(n),且要求不能用非基于比较的排序。

    这个问题是要求不能用非基于比较的排序,那如果用非基于比较的排序如何做?

    思路如下:

    对于 N 个数,准备 N + 1 个桶,目的是预留一个空桶,此后有大作用。

    遍历数组,找到数组的最大值 max 和最小值 min,如果 max == min,返回 0;否则,按照桶排序的规则划分成 N + 1 个数据范围。

    此时 N + 1 个桶装 N 个数,一定会存在一个空桶,这时候有一个推论,相邻两个数的最大差值一定不来自同一个桶

    • 空桶不可能是第一个桶和最后一个桶
    • 空桶左右肯定是非空桶
    • 空桶左桶的 max 值和右桶的 min 值的差值一定大于空桶的容纳数的范围

    桶需要记录三个参数,桶是否存过数 boolean,桶中数字最大值和最小值。

    所以在将一个个数填入桶时,及时更新桶中数字最大值和最小值。

    最后遍历桶,在遍历过程中记录一个全局变量最大差值。遇到非空桶则取出此桶的最小值和上一个非空桶的最大值,此时如果差值比全局变量大,则更新全局变量。

    问题:

    为什么不求空桶两侧?

    空桶两侧的数据不一定是最大差值,因为一个桶的范围如果是 d,则空桶两侧的数值差最小可为 d + 2,而相邻的非空桶最大差值可为 2d - 2。不能保证 d + 2 必定大于 2d - 2。预留一个桶的设计目的是为了推出最大差值是来自不同桶的结论,而不能推出来自空桶两侧的结论。

    实现:

    public static int maxGroup(int[] arr) {
        if (arr == null || arr.length < 2) return 0;
    
        //查找数组最大值和最小值
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int len = arr.length;
        for (int i = 0; i < len; i++) {
            max = Math.max(max, arr[i]);
            min = Math.min(min, arr[i]);
        }
        if (max == min) return 0;
    
        //创建桶中三个存储的信息
        boolean[] hasNum = new boolean[len + 1];
        int[] maxNum = new int[len + 1];
        int[] minNum = new int[len + 1];
    
        //遍历更新桶中的信息
        for (int i = 0; i < len; i++) {
            int index = bucket(arr[i], min, max, len);
            //此处可避免初始化数组的值的影响
            maxNum[index] = hasNum[index] ? Math.max(maxNum[index], arr[i]) : arr[i];
            minNum[index] = hasNum[index] ? Math.min(minNum[index], arr[i]) : arr[i];
            hasNum[index] = true;
        }
    
        //遍历得到相邻两个数的最大差值
        int res = 0;
        int lastMax = maxNum[0];
        //注意此处的 i 从 1 开始,遍历的是桶,桶长度是 len + 1
        for (int i = 1; i <= len; i++) {
            if (hasNum[i]) {
                res = Math.max(res, minNum[i] - lastMax);
                lastMax = maxNum[i];
            }
        }
        return res;
    }
    
    public static int bucket(int number, int min, int max, int length) {
        return (int) (number - min) * length / (max - min);
    }
    
  • 相关阅读:
    归一化与标准化的概念与区别
    深度学习中的优化器学习
    yolo3与yolo-tiny
    给tensorflow1.x estimator 添加timeline分析性能
    python 爬取百度图片
    TensorFlow 高性能数据输入管道设计指南
    TensorRT加速tensorflow模型(使用Tensorflow内置tensorRT,避免写自定义Plugin)
    21.Pod的limit和request和资源监控收集服务Heapster
    20.调度器,预选策略和优选策略
    8.docker的安全性
  • 原文地址:https://www.cnblogs.com/chenxianbin/p/11912925.html
Copyright © 2011-2022 走看看