1. 程式人生 > >Java常用的八種排序演算法與程式碼實現(三):桶排序、計數排序、基數排序

Java常用的八種排序演算法與程式碼實現(三):桶排序、計數排序、基數排序

三種線性排序演算法:桶排序、計數排序、基數排序

線性排序演算法(Linear Sort):這些排序演算法的時間複雜度是線性的O(n),是非比較的排序演算法

桶排序(Bucket Sort)
  將要排序的資料分到幾個有序的桶裡,每個桶裡的資料再單獨進行排序,桶內排完序之後,再把桶裡的資料按照順序取出,組成的序列就是有序的了
桶排序比較適合用在外部排序中,比如磁碟中的資料需要   排序而記憶體有限,沒有辦法將資料全部載入的情況
桶排序步驟:
  1.找出待排序陣列中的最大值max、最小值min
  2. 動態陣列ArrayList 作為桶,桶裡放的元素也用 ArrayList 儲存。桶的數量為(max-min)/arr.length+1
  3.遍歷陣列 arr,計算每個元素 arr[i] 放的桶
  4.每個桶各自排序
  5.遍歷桶陣列,把排序好的元素放進輸出陣列
圖解:
在這裡插入圖片描述

在這裡插入圖片描述
程式碼:

/**
   * 桶排序
   *
   * @param arr 待排陣列
   */
  public static void bucketSort(int[] arr) {
    int min = arr[0];
    int max = arr[0];
    // 獲取資料範圍
    for (int i = 1; i < arr.length; i++) {
      if (arr[i] > max) {
        max = arr[i];
      }
      if (arr[i] < min) {
        min = arr[i];
      }
    }
    // 確定桶數
    int count = (min + max) / arr.length + 1;
    ArrayList<ArrayList<Integer>> bucket = new ArrayList<>(count);
    for (int i = 0; i < count; i++) {
      bucket.add(new ArrayList<>());
    }
    // 將元素放入桶
    for (int i = 0; i < arr.length; i++) {
      int num = (arr[i] - min) / arr.length;
      bucket.get(num).add(arr[i]);
    }
    // 將桶中資料進行排序(排序已經完成)
    for (ArrayList<Integer> arrayList : bucket) {
      Collections.sort(arrayList);
    }
    // 將桶中資料匯入待排序的陣列中(只是為了顯示方便)
    int k = 0;
    for (int i = 0; i < bucket.size(); i++) {
      for (int j = 0; j < bucket.get(i).size(); j++) {
        arr[k++] = bucket.get(i).get(j);
      }
    }
  }

計數排序(Counting Sort)
  桶排序的一種特殊情況,當要排序的n個數據,所處的範圍並不大的時候,比如最大值是k,我們就可以把資料劃分成k個桶,每個桶的表資料值都是相同的,省掉了桶內排序的步驟,在顯示生活中也存在這樣的案例,比如高考省榜,就是按照這種排序方式進行排列的(主要適用於資料比較集中的情況)

計數排序步驟:
  1 求出待排序列的最大值和最小值
  2 設定一個計數陣列,用來記錄每個元素出現的次數
  3 記錄待排序列在計數陣列中的位置和次數
  4 將計數陣列中的資料灌入待排序列中
圖解:
在這裡插入圖片描述  計數排序在生活中的應用:—— 高考省榜
在這裡插入圖片描述
程式碼:

/**
   * 計數排序
   *
   * @param arr 待排陣列
   */
  public static void countingSort(int[] arr) {
    int min = arr[0];
    int max = arr[0];
    // 獲取資料範圍
    for (int i = 1; i < arr.length; i++) {
      if (arr[i] > max) {
        max = arr[i];
      }
      if (arr[i] < min) {
        min = arr[i];
      }
    }
    // 建立計數陣列count,用來記錄資料出現的次數
    int[] count = new int[max - min + 1];
    for (int i = 0; i < arr.length; i++) {
      count[arr[i] - min]++;
    }
    // 將計數陣列中的資料灌入待排序陣列
    int k = 0;
    for (int i = 0; i < count.length; i++) {
      if (count[i] != 0) {
        for (int j = 0; j < count[i]; j++) {
          arr[k++] = i + min;
        }
      }
    }
  }

基數排序(Radix Sort)
  基數排序對要排序的資料有要求,需要可以分割出獨立的”位”進行比較,而且位與位之間有遞進關係,如果a資料的高位比b資料大,那剩下的地位就不用比較了,除此之外每一位的資料範圍不能太大,要可以用線性排序演算法來排序,否則基數排序的時間複雜度就無法做到O(n)

基數排序的步驟:
  1 找出待排序列的未排高位
  2 用線性排序按照未排高位進行線性排序,然後重複1過程,直至序列全部有序
圖解:
在這裡插入圖片描述
程式碼:

/**
   * 基數排序
   *
   * @param arr 待排陣列
   * @param len 待排位數
   */
  public static void radixSort(int[] arr, int len) {
    // 除數,從8位0開始,先比較高位
    int divisor = (int) Math.pow(10, len);
    // 確定桶數,桶的數量可設為10,因為位數的取值為0-9,並初始化桶
    ArrayList<ArrayList<Integer>> bucket = new ArrayList<>(10);
    for (int i = 0; i < 10; i++) {
      bucket.add(new ArrayList<>());
    }
    for (int i = 0; i < arr.length; i++) {
      // 只取個位
      int c = (arr[i] / divisor) % 10;
      bucket.get(c).add(arr[i]);
    }
    // 將桶中資料進行排序(排序已經完成)
    for (ArrayList<Integer> arrayList : bucket) {
      Collections.sort(arrayList);
    }
    // 將桶中資料匯入待排序的陣列中
    int k = 0;
    for (int i = 0; i < bucket.size(); i++) {
      for (int j = 0; j < bucket.get(i).size(); j++) {
        arr[k++] = bucket.get(i).get(j);
      }
    }
  }

測試類及生成隨機陣列,隨機訂單的方法(基數排序的資料是50個8位訂單號)

/**
   * 生成一個長度5-10的隨機陣列
   *
   * @return 隨機陣列
   */
  private static int[] initArray() {
    int len = 5 + new Random().nextInt(6);
    int[] arr = new int[len];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = new Random().nextInt(100);
    }
    return arr;
  }

  /**
   * 為基數排序法準備的8位隨機訂單,50組資料
   *
   * @return 隨機訂單陣列
   */
  private static int[] initArrayForRadixSort() {
    String str = "";
    int[] arr = new int[50];
    Random random = new Random();
    for (int i = 0; i < arr.length; i++) {
      // 保證訂單首位數不為0,所以隨機0-9生成後7位,隨機1-9生成第一位
      for (int j = 0; j < 7; j++) {
        str += random.nextInt(10);
      }
      str = 1 + random.nextInt(9) + str;
      arr[i] = Integer.valueOf(str);
      str = "";
    }
    return arr;
  }

public static void main(String[] args) {

    // 基數排序
    int[] arr = initArrayForRadixSort();
    System.out.println("排序之前的陣列是:" + Arrays.toString(arr));
    int count = (arr[0] + "").length() - 1;
    for (int i = count; i < arr.length; i++) {
      countingSort(arr, i);
    }
    System.out.println("排序之後的陣列是:" + Arrays.toString(arr));

    // 非基數排序
   int[] arr2 = initArray();
    System.out.println("排序之前的陣列是:" + Arrays.toString(arr2));
    quockSort(arr2);
    System.out.println("排序之後的陣列是:" + Arrays.toString(arr2));
  }

測試結果,親測有效:

桶排序:
  排序之前的陣列是:[31, 64, 46, 94, 29, 99, 82, 48, 84]
  排序之後的陣列是:[29, 31, 46, 48, 64, 82, 84, 94, 99]
計數排序:
  排序之前的陣列是:[11, 20, 56, 2, 47, 75, 66, 21, 3, 74]
  排序之後的陣列是:[2, 3, 11, 20, 21, 47, 56, 66, 74, 75]
基數排序:
  排序之前的陣列是:[54920007, 10744441, 24003637, 22072166, 12466348, 17322066, 54489715, 64847150, 48366735, 80287146, 71463179, 82992316, 74996232, 37427568, 45629716, 71177033, 81944062, 74519384, 91743758, 68246062, 23798432, 96894141, 69555229, 49967525, 52587116, 43508294, 47269398, 97352691, 82058781, 67895293, 11909501, 30869797, 47345049, 50743493, 25530908, 85030153, 16247011, 76036389, 10846207, 88061686, 17767234, 25997527, 98880748, 26860131, 98633987, 88621984, 89076873, 70419980, 95812196, 21624491]
  排序之後的陣列是:[10744441, 10846207, 11909501, 12466348, 16247011, 17322066, 17767234, 21624491, 22072166, 23798432, 24003637, 25530908, 25997527, 26860131, 30869797, 37427568, 43508294, 45629716, 47269398, 47345049, 48366735, 49967525, 50743493, 52587116, 54489715, 54920007, 64847150, 67895293, 68246062, 69555229, 70419980, 71177033, 71463179, 74519384, 74996232, 76036389, 80287146, 81944062, 82058781, 82992316, 85030153, 88061686, 88621984, 89076873, 91743758, 95812196, 96894141, 97352691, 98633987, 98880748]

8種排序演算法程式碼:https://github.com/lijialin0903/sort.git