分治法算法中的經典——歸併排序
上一節,我講了分治法的相關思想,並貼出數字旋轉方陣的代碼以及解決思想。算法的話,主要還是要靠自己領悟,要多思考,不會再去看看別人的思路。以下,我分析一下分治法算法中的經典——歸併排序。
下面舉個例子:
有個int數組,元素爲{1,6,2,7,4,9}
首先,我們先將整個數組分解,分解成一個個規模大小相同的子問題,直到只有一個元素(圖中第四行)。現在,我們再進行合併(圖中第五六七行)。
合併的時候,就是將兩個數組不斷進行合併。以下是我的代碼,裏面有詳細的註釋。
show you my code :
import java.util.Scanner;
/**
* 歸併排序
*
* @author chenjuxnu
* @since 2016-1-20
*
*/
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
/** 輸入數組的長度 */
int num = scan.nextInt();
/** 用於存放數據的數組 */
int arr[] = new int[num];
/** 用於合併數據的數組 */
int result[] = new int[num];
/** 將控制檯的內容輸入至數組內 */
for (int i = 0; i < num; i++) {
arr[i] = scan.nextInt();
}
scan.close();
/** 調用歸併方法 */
MergeSort(0, num - 1, arr, result);
/** 輸出內容 */
for (int i = 0; i < num; i++) {
System.out.print(result[i] + " ");
}
}
/**
* 歸併排序的遞歸方法
*
* @param start
* 數組的開始值
* @param end
* 數組的結束值
* @param arr
* 存放用戶輸入數據的數組
* @param result
* 用於存放合併後的數組
*/
public static void MergeSort(int start, int end, int arr[], int result[]) {
/** 用於保存中間值 */
int m;
// 如果開始下標等於結束下標,則結束遞歸
if (start == end) {
return;
} else {
m = (start + end) / 2;
// 遞歸調用左部分數據
MergeSort(start, m, arr, result);
// 遞歸調用右部分數據
MergeSort(m + 1, end, arr, result);
// 合併數組
Merge(arr, start, m, end, result);
// 將排序好的子序列放會到arr數組裏
for (int i = start; i <= end; i++) {
arr[i] = result[i];
}
}
}
/**
* 用於合併數組的內容,並放到result數組內
*
* @param arr
* 需要合併的數組
* @param start
* 需要合併的數組的開始下標
* @param mid
* 需要合併的數組的(開始下標+結束下標)/2
* @param end
* 需要合併的數組的結束下標
* @param result
* 用於存放合併後的數組
*/
public static void Merge(int arr[], int start, int mid, int end,
int result[]) {
/** 用於記錄需要合併的第二個數組的下標 */
int j = mid + 1;
/** 用於記錄result數組的下標 */
int num = start;
// 如果需要合併的第一個數組跟第二個數組均有數值可以比較
while (start <= mid && j <= end) {
if (arr[start] < arr[j]) {
result[num++] = arr[start++];
} else {
result[num++] = arr[j++];
}
}
// 如果需要合併的第二個數組沒數值了,就將第一個數組依次放入result數組內
while (start <= mid) {
result[num++] = arr[start++];
}
// 如果需要合併的第一個數組沒數值了,就將第二個數組依次放入result數組內
while (j <= end) {
result[num++] = arr[j++];
}
}
}