• java实现各种排序算法(非比较排序)


    前言

    之前学习了基于比较的各种排序算法java实现各种排序算法(比较排序),今天再学习一下非比较排序。

    计数排序

    代码实现

    以对所有学生的成绩排序为例

    import java.util.Arrays;
    import java.util.Random;
    
    public class CountingSort {
    
      public void sort(int[] nums) {
        //成绩的范围为[0,100]
        int[] scores = new int[101];
        for (int num : nums) {
          scores[num]++;
        }
        int index = 0;
        for (int score = 0; score < scores.length; score++) {
          //scores[score]的值为score分数的学生人数
          for (int i = 0; i < scores[score]; i++) {
            nums[index++] = score;
          }
        }
      }
    
      public static void main(String[] args) {
        //生成一个包含50个元素的数组(每个元素小于等于100)
        int[] arr = generateRandomArr(50, 101);
        System.out.println(Arrays.toString(arr));
        new CountingSort().sort(arr);
        System.out.println(Arrays.toString(arr));
      }
    
      private static int[] generateRandomArr(int n, int bound) {
        Random random = new Random();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
          arr[i] = random.nextInt(bound);
        }
        return arr;
      }
    
    }
    

    统统计出每个成绩的学生个数,如60分学生有10个,61分学生有20个。计数排序适用于数据范围比较小的情况,如学生成绩,年龄等。时间复杂度O(N)。

    应用

    leetcode75. 颜色分类

    基数排序

    import java.util.Arrays;
    
    public class LSDSort {
    
      public void sort(String[] arr) {
        if (arr.length == 0) {
          return;
        }
        int length = arr[0].length();
        for (String s : arr) {
          if (s.length() != length) {
            throw new IllegalArgumentException("All Strings' length must be the same.");
          }
        }
        int R = 256;
        int[] counts = new int[R];
        String[] temp = new String[arr.length];
        int[] countIndexs = new int[R];
        for (int r = length - 1; r >= 0; r--) {
          //对每一位进行计数排序
          Arrays.fill(counts, 0);
          for (String s : arr) {
            counts[s.charAt(r)]++;
          }
          for (int i = 0; i < R; i++) {
            if (i == 0) {
              countIndexs[i] = 0;
            } else {
              countIndexs[i] = countIndexs[i - 1] + counts[i - 1];
            }
          }
          for (String s : arr) {
            temp[countIndexs[s.charAt(r)]] = s;
            countIndexs[s.charAt(r)]++;
          }
          System.arraycopy(temp, 0, arr, 0, arr.length);
        }
      }
    
      public static void main(String[] args) {
    
        String[] arr = {"BCA", "CAB", "ACB", "BAC", "ABC", "CBA"};
        new LSDSort().sort(arr);
        for (String s : arr) {
          System.out.println(s);
        }
      }
    }
    

    从低位开始,对每一位进行计数排序,适用于等长字符串,如车牌号,手机号等。

    桶排序

    还是以对所有学生的成绩排序为例,分成10个桶,第一个桶成绩区间为[0-9],第二个为[10-19],依次类推

    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.List;
    
    public class BucketSort {
    
      public void sort(int[] nums) {
        //成绩的范围为[0,100] 桶大小为10  11个桶
        int bucketSize = 10;
        int scoreRange = 101;
        int bucketCount = scoreRange / bucketSize + (scoreRange % bucketSize == 0 ? 0 : 1);
        List<Integer>[] bucketList = new List[bucketCount];
        for (int i = 0; i < bucketList.length; i++) {
          bucketList[i] = new LinkedList<>();
        }
        for (int num : nums) {
          bucketList[getBucketIndex(num, bucketSize)].add(num);
        }
        List<Integer> res = new LinkedList<>();
        for (List<Integer> list : bucketList) {
          int[] array = list.stream().mapToInt(x -> x).toArray();
          insertSort(array);
          for (int val : array) {
            res.add(val);
          }
        }
        int index = 0;
        for (Integer val : res) {
          nums[index++] = val;
        }
      }
    
      private int getBucketIndex(int num, int bucketSize) {
        return num / bucketSize;
      }
    
      private void insertSort(int[] nums) {
        //[0,i)为已排序的,[i,n)为未排序的
        for (int i = 1; i < nums.length; i++) {
          int insertValue = nums[i];
          int j = i - 1;
          while (j >= 0 && insertValue < nums[j]) {
            nums[j + 1] = nums[j];
            j--;
          }
          nums[j + 1] = insertValue;
        }
      }
    
      public static void main(String[] args) {
        int[] nums = {12, 56, 87, 99, 64, 5, 23};
        new BucketSort().sort(nums);
        System.out.println(Arrays.toString(nums));
      }
    
    }
    

    学生成绩区间为[0,100],每个桶区间为10,对每个桶内元素进行插入排序,然后所有桶中元素顺序拿出来即可。桶排序适用于数据分布均匀的情况。

    总结

    • 计数排序可以看做桶排序的特例,当每个桶大小为1时,就变成了计数排序。
    • 基数排序可以看做多轮计数排序,对每个有效位都进行一次计数排序。
    • 这三种排序算法都需要额外的辅助空间,且对输入数据有要求,只能在特定情况下使用。

    参考

    计数排序、基数排序和桶排序

  • 相关阅读:
    unittest用法和report输出
    python断言方式
    python闭包等
    html 基础
    Python装饰器
    python递归取出n层嵌套列表里的所有元素
    pycharm问题集锦
    Coding the Futurn
    python3-端口扫描(TCP_ACK扫描,NULL扫描,windows扫描,xmas扫描)
    python3-端口扫描(TCP connect扫描,SYN扫描,FIN扫描)
  • 原文地址:https://www.cnblogs.com/strongmore/p/16275023.html
Copyright © 2020-2023  润新知