1. 程式人生 > 其它 >java實現各種排序演算法(非比較排序)

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時,就變成了計數排序。
  • 基數排序可以看做多輪計數排序,對每個有效位都進行一次計數排序。
  • 這三種排序演算法都需要額外的輔助空間,且對輸入資料有要求,只能在特定情況下使用。

參考

計數排序、基數排序和桶排序