分治策略對數組進行排序(二分排序算法)

分治策略對數組進行排序(二分排序算法)

今天我來熟悉鞏固一下分治算法對數組進行排序,分治問題就是把複雜的大問題拆解成簡單的小問題,再將小問題依次解決,假設我們要對下面這個數組進行排序輸出:

[ 32, 11, 22, 17, 222, 42, 162, 82, 1, 1231, 12, 2 ]

如果使用分治策略的話,我們需要先將大問題分解成小問題,我們可以先將長度 12 的數組分解爲兩個長度爲 6 的數組,分解後如下

[ 32, 11, 22, 17, 222, 42 ]
[ 162, 82, 1, 1231, 12, 2 ]

分解過後是否可以直接進行排序了呢?好像還是不太行,那麼我們可以繼續分解,分解到可以直接進行比較爲止

// 第二次分解
[ 32, 11, 22 ] 
[ 17, 222, 42 ] 

[ 162, 82, 1 ] 
[ 1231, 12, 2 ]

// 第三次分解

[ 32, 11 ]
[ 22 ]

[ 17, 222 ]
[ 42 ]

[ 162, 82 ]
[ 1 ]

[ 1231, 12 ]
[ 2 ]

// 第四次分解

[ 32 ]
[ 11 ]

[ 22 ]

[ 17 ]
[ 222 ]

[ 42 ]

[ 162 ]
[ 82 ]

[ 1 ]

[ 1231 ]
[ 12 ]

[ 2 ]

我們的最終目標是將複雜數組分解成爲長度爲 1 的小數組,這樣我們就可以直接對兩個數組進行比較,比如 [32][11] 比較,此時應該進入一個循環,比較兩個數組的首個元素,比較完成後將其合併得到 [ 11, 32 ],再使用 [ 11, 32 ][ 22 ] 比較數組的首個元素大小,比較完成後進行合併得到 [ 11, 22, 32 ],以此類推,最後得到的將會是一個排序完成的。

我們將上面的分析進行步驟劃分,我們應該需要實現兩個功能:

  • 將複雜數組劃分爲原子級別的簡單數組;
  • 將原子級別的數組進行比對後依次合併,重新組成排序好的複雜數組;

我們現在來進行代碼的實現,首先我們創建一個接口來形容這個排序算法類

public interface Sort {
    public int[] sort(int[] arr);
}

然後我們來編輯這個類的實現,最後的調用效果應該是這樣的:

import java.util.Arrays;

public class DivisionSort implements Sort {
  @Override
  public int[] sort(int[] arr) {
      //...
      return arr;
  }
  public static void main(String[] args) {
    int[] arr = new int[] { 32, 11, 22, 17, 222, 42, 162, 82, 1, 1231, 12, 2 };
    Sort divisionSort = new DivisionSort();
    int[] sortedArr = divisionSort.sort(arr);
    System.out.println(Arrays.toString(sortedArr));
  }
}

我們現在先進行第一步,將複雜數組分解爲簡單數組:

private void splitArr(int[] arr, int start, int end) {
  // 當數組開始位置等於結束位置才停止分割(此時數組長度爲 1)
  if (end != start) {
    // 取中點位置,遞歸調用將數組分爲兩份
    int mid = (end + start) / 2;
    splitArr(arr, start, mid);
    splitArr(arr, mid + 1, end);
  }
}

分解的函數就是一個遞歸調用,遞歸將數組分割爲原子級別,而合併的函數,我們可以好好想一下,如何對比 [ 11, 32 ][ 22 ],應該依次取出兩個數組的第一個元素,比對完成後將較小的一個推入合併後的數組。

所以這裏應該是先比較 11 和 22 的大小,然後將 11 推入合併後的數組,比較完成後再比較 32 和 22,然後將 22 推入合併後的數組,最後的比較將會判斷到某個數組已經無元素可對比,那麼另一個數組剩餘的數字均是大數,直接推入合併後的數組即可,那麼實現出來以後就是:

private void mergeArr(int[] arr, int start, int end) {
  // 將數組分爲左右兩邊進行對比
  // 比如 { 11 32 22 } 將被分爲 { 11 32 } 和 { 22 } 兩個數組
  int mid = (start + end) / 2;
  int[] leftArr = Arrays.copyOfRange(arr, start, mid + 1);
  int[] rightArr = Arrays.copyOfRange(arr, mid + 1, end + 1);
  int i = 0, j = 0;
  for (int k = start; k <= end; k++) {
      // 判斷數組是否已經沒有多餘元素
      if (i == leftArr.length) {
          arr[k] = rightArr[j];
          j++;
          continue;
      }

      if (j == rightArr.length) {
          arr[k] = leftArr[i];
          i++;
          continue;
      }

      if (leftArr[i] < rightArr[j]) {
          arr[k] = leftArr[i];
          i++;
      } else {
          arr[k] = rightArr[j];
          j++;
      }
  }
}

最後組成後的 DivisionSort 類就是這個樣子的:

import java.util.Arrays;

public class DivisionSort implements Sort {
    @Override
    public int[] sort(int[] arr) {
        this.splitArr(arr, 0, arr.length - 1);
        return arr;
    }

    private void splitArr(int[] arr, int start, int end) {
        if (end != start) {
            int mid = (end + start) / 2;
            splitArr(arr, start, mid);
            splitArr(arr, mid + 1, end);
            mergeArr(arr, start, end);
        }
    }

    private void mergeArr(int[] arr, int start, int end) {
        int mid = (start + end) / 2;
        int[] leftArr = Arrays.copyOfRange(arr, start, mid + 1);
        int[] rightArr = Arrays.copyOfRange(arr, mid + 1, end + 1);
        int i = 0, j = 0;
        for (int k = start; k <= end; k++) {
            if (i == leftArr.length) {
                arr[k] = rightArr[j];
                j++;
                continue;
            }

            if (j == rightArr.length) {
                arr[k] = leftArr[i];
                i++;
                continue;
            }

            if (leftArr[i] < rightArr[j]) {
                arr[k] = leftArr[i];
                i++;
            } else {
                arr[k] = rightArr[j];
                j++;
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[] { 32, 11, 22, 17, 222, 42, 162, 82, 1, 1231, 12, 2 };
        Sort divisionSort = new DivisionSort();
        int[] sortedArr = divisionSort.sort(arr);
        System.out.println(Arrays.toString(sortedArr));
    }
}

最後輸出的結果爲 [1, 2, 11, 12, 17, 22, 32, 42, 82, 162, 222, 1231],排序完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章