分治法算法中的经典——归并排序
上一节,我讲了分治法的相关思想,并贴出数字旋转方阵的代码以及解决思想。算法的话,主要还是要靠自己领悟,要多思考,不会再去看看别人的思路。以下,我分析一下分治法算法中的经典——归并排序。
下面举个例子:
有个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++];
}
}
}