zoukankan      html  css  js  c++  java
  • 算法练习(5)-计数排序法及优化

    日常开发中,会遇到一些特定的排序场景:“待排序的值”范围很明细,比如:基金的星级排名,客服的好评星级排名,一般星级排名也就从1星到5星。这种情况下,有一个经典的“下标计数排序法”,可以用O(n)的时间复杂度完成排序:

        static void sort0() {
            int[] arr = new int[]{5, 4, 4, 1, 2, 3};
            int[] indexCountArr = new int[6];
    
            //下标计数排序
            for (int i = 0; i < arr.length; i++) {
                indexCountArr[arr[i]] += 1;
            }
            //排完后,indexCountArr的值:[0, 1, 1, 1, 2, 1]
            System.out.println("indexCountArr=>" + Arrays.toString(indexCountArr));
            
            //排序结果输出
            for (int i = 0; i < indexCountArr.length; i++) {
                for (int j = 0; j < indexCountArr[i]; j++) {
                    System.out.print(i + "	");
                }
            }
            System.out.println("
    ");
        }
    

    输出:

    indexCountArr=>[0, 1, 1, 1, 2, 1]
    1 2 3 4 4 5

    但这是一个不稳定的排序算法,而且输出结果只有值,如果是一个复杂的对象,比如下面这样:

        static class EmpScore {
            public String empNo;
            public int score;
    
            public EmpScore(String empNo, int score) {
                this.empNo = empNo;
                this.score = score;
            }
    
            @Override
            public String toString() {
                return empNo + ":" + score;
            }
        }
    
        public static void main(String[] args) {
            EmpScore[] arr = new EmpScore[]{
                    new EmpScore("S01", 5),
                    new EmpScore("S02", 4),
                    new EmpScore("S03", 4),
                    new EmpScore("S04", 1),
                    new EmpScore("S05", 2),
                    new EmpScore("S06", 3)
            };
    
            //todo 待排序
        }
    

    按score评分星级排序后,如果希望S02仍然在S03前面,可以参考下面这样:(大致思路是在每个"桶"的位置,引入了一个顺序结构的List)

        static void sort1(EmpScore[] arr) {
            //排序过程(下标计数排序)
            Map<Integer, List<EmpScore>> scoreMap = new HashMap<>(arr.length);
            int[] indexCountArr = new int[6];
            for (int i = 0; i < arr.length; i++) {
                indexCountArr[arr[i].score] += 1;
                List<EmpScore> list;
                if (scoreMap.containsKey(arr[i].score)) {
                    list = scoreMap.get(arr[i].score);
                } else {
                    list = new ArrayList<>();
                }
                list.add(arr[i]);
                scoreMap.put(arr[i].score, list);
            }
            //排完后,indexCountArr的值:[0, 1, 1, 1, 2, 1]
            System.out.println("indexCountArr=>" + Arrays.toString(indexCountArr));
    
            //输出结果
            List<EmpScore> sortedList = new ArrayList<>(arr.length);
            for (int i = 1; i < indexCountArr.length; i++) {
                sortedList.addAll(scoreMap.get(i));
            }
            System.out.println(sortedList.toString() + "
    ");
        }
    

    输出:

    indexCountArr=>[0, 1, 1, 1, 2, 1]
    [S04:1, S05:2, S06:3, S02:4, S03:4, S01:5]

    如果不想额外引入List,还可以这样做:

    static void sort2(EmpScore[] arr) {
        int[] indexCountArr = new int[6];
        for (int i = 0; i < arr.length; i++) {
            indexCountArr[arr[i].score] += 1;
        }
        //关键点1
        for (int i = 1; i < arr.length; i++) {
            indexCountArr[i] += indexCountArr[i - 1];
        }
    
        //排完后,indexCountArr的值:[0, 1, 2, 3, 5, 6]
        System.out.println("indexCountArr=>" + Arrays.toString(indexCountArr));
    
        EmpScore[] sorted = new EmpScore[arr.length];
        //关键点2
        for (int i = arr.length - 1; i >= 0; i--) {
            sorted[indexCountArr[arr[i].score] - 1] = arr[i];
            indexCountArr[arr[i].score] -= 1;
        }
    
        System.out.println(Arrays.toString(sorted));
    }
    

    结果不变,具体过程,大家可以拿张纸,自己画一画,还是蛮有技巧的,算是一种比较tricky的解法吧。

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    C# 基于密钥的64位加密与解密方法(原创)
    爱情 前途 命运
    设计模式学习笔记装饰模式
    jquery暂无图片插件
    IIS GZIP压缩(转)
    Fckeditor使用笔记
    设计模式学习笔记策略模式
    电子商务网站搜索架构方案
    批量修改数据库表的架构sql
    win 2003 安装 vs2005 sp1 问题1718
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/14535037.html
Copyright © 2011-2022 走看看