栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

桶排序 + 排序稳定性及总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

桶排序 + 排序稳定性及总结

桶排序

桶排序思想下的排序:计数排序 & 基数排序

1)桶排序思想下的排序都是不基于比较的排序

2)时间复杂度为O(N),额外空间负载度O(M)

3)应用范围有限,需要样本的数据状况满足桶的划分

1)一般来讲,计数排序要求,样本是整数,且范围比较窄(员工年龄)
2)一般来讲,基数排序要求,样本是10进制的正整数
一旦要求稍有升级,改写代价增加是显而易见的

计数排序

public class CountSort {

    //对员工年龄进行排序
    public static void sort(int[] ages){
        if(ages ==null || ages.length < 2){
            return;
        }
        //1.找出最大年龄
        int maxAge = Integer.MIN_VALUE;
        for (int age : ages) {
            maxAge = Math.max(maxAge,age);
        }
        //辅助数组
        int[] help = new int[maxAge + 1];
        for (int i = 0; i < ages.length; i++) {
            help[ages[i]]++;
        }
        //遍历辅助数组,把数组放到ages中
        int i = 0;
        for (int j = 0; j < help.length; j++) {
            while (help[i]-- >0){
                ages[i++] = j;
            }
        }

    }
}

基数排序

package com.lzf2.class07;

import java.util.Arrays;


public class RadixSort {
    // only for no-negative value
    public static void radixSort(int[] arr){
        if(arr==null || arr.length < 2){
            return;
        }
        radixSort(arr,0,arr.length - 1,maxbits(arr));
    }
    //最大数有多少位
    public static int maxbits(int[] arr){
        int max = Integer.MIN_VALUE;
        for (int i : arr) {
             max = Math.max(max,i);
        }
        int res = 0;
        while (max != 0){
            res++;
            max /= 10;
        }
        return res;
    }
    public static int getDigit(int x, int d) {
        return ((x / ((int) Math.pow(10, d - 1))) % 10);
    }
    // arr[L..R]排序  ,  最大值的十进制位数digit
    public static void radixSort(int[] arr, int L, int R, int digit) {
        int radix = 10;//基数
        int[] help = new int[R - L + 1];
        for (int d = 1; d <= digit; d++) {//有多少位就进出多少次

            int[] count = new int[radix];//统计该位上每个数字的个数
            for (int i = L; i <= R; i++) {
                int num = getDigit(arr[i],d);
                count[num]++;
            }
            //把count改成累加和
            for (int i = 1; i < radix; i++) {
                count[i] = count[i] + count[i - 1];
            }
            //从由往左遍历原数组,调整好位置
            for (int i = R; i >= L; i--) {
                int num = getDigit(arr[i],d);
                help[count[num] - 1] = arr[i];
                count[num]--;
            }
            //辅助数组拷贝回原数组
            for (int i = L,j = 0; i <= R; i++,j++) {
                arr[i] = help[j];
            }
        }


    }


    // for test
    public static void comparator(int[] arr) {
        Arrays.sort(arr);
    }

    // for test
    public static int[] generateRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random());
        }
        return arr;
    }

    // for test
    public static int[] copyArray(int[] arr) {
        if (arr == null) {
            return null;
        }
        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }

    // for test
    public static boolean isEqual(int[] arr1, int[] arr2) {
        if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
            return false;
        }
        if (arr1 == null && arr2 == null) {
            return true;
        }
        if (arr1.length != arr2.length) {
            return false;
        }
        for (int i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]) {
                return false;
            }
        }
        return true;
    }

    // for test
    public static void printArray(int[] arr) {
        if (arr == null) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println();
    }

    // for test
    public static void main(String[] args) {
        int testTime = 500000;
        int maxSize = 100;
        int maxValue = 100000;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr1 = generateRandomArray(maxSize, maxValue);
            int[] arr2 = copyArray(arr1);
            radixSort(arr1);
            comparator(arr2);
            if (!isEqual(arr1, arr2)) {
                succeed = false;
                printArray(arr1);
                printArray(arr2);
                break;
            }
        }
        System.out.println(succeed ? "Nice!" : "Fucking fucked!");

        int[] arr = generateRandomArray(maxSize, maxValue);
        printArray(arr);
        radixSort(arr);
        printArray(arr);

    }
}
排序的稳定性

稳定性是指同样大小的样本再排序之后不会改变相对次序

对基础类型来说,稳定性毫无意义

对非基础类型来说,稳定性有重要意义

有些序算法可以实现成稳定的, 而有些排序算法无论如何都实现不成稳定的

排序总结

1)不基于比较的排序,对样本数据有严格要求,不易改写
2)基于比较的排序,只要规定好两个样本怎么比大小就可以直接复用
3)基于比较的排序,时间复杂度的极限是O(NlogN)
4)时间复杂度O(N
logN)、额外空间复杂度低于O(N)、且稳定的基于比较的排序是不存在的。
5)为了绝对的速度选快排、为了省空间选堆排、为了稳定性选归并

常见的坑

1)归并排序的额外空间复杂度可以变成O(1),“归并排序 内部缓存法”,但是将变得不再稳定。

2)“原地归并排序" 是垃圾贴,会让时间复杂度变成O(N^2)

3)快速排序稳定性改进,“01 stable sort”,但是会对样本数据要求更多。

在整型数组中,请把奇数放在数组左边,偶数放在数组右边,要求所有奇数之间原始的相对次序不变,所有偶数之间原始相对次序不变。时间复杂度做到O(N),额外空间复杂度做到O(1)。

做不到

1)归并排序的额外空间复杂度可以变成O(1),“归并排序 内部缓存法”,但是将变得不再稳定。

2)“原地归并排序" 是垃圾贴,会让时间复杂度变成O(N^2)

3)快速排序稳定性改进,“01 stable sort”,但是会对样本数据要求更多。

在整型数组中,请把奇数放在数组左边,偶数放在数组右边,要求所有奇数之间原始的相对次序不变,所有偶数之间原始相对次序不变。时间复杂度做到O(N),额外空间复杂度做到O(1)。

做不到

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/320074.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号