package algorithm.sort;
/**
* 合并(归并)排序:按照分治模式,操作如下:
* 分解:将n个元素分成各含n/2个元素的子序列
* 解决:用合并排序法对两个子序列递归排序
* 合并:合并两个已经排序的子序列已得到排序结果
* @author Administrator
*/
public class MergeSort {
/**
* 合并排序的关键在于合并两个已经排好序的子序列
* a[from, mid],a[mid+a, end]已排好序,合并成已排序的数组代替a[from, end]
* @param a
* @param from
* @param end
* @param mid
*/
//方法一:在过程中利用最大值作为哨兵值,来避免检查每个子序列是否为空
//一旦两个子序列都出现这个哨兵值,说明所有的值都已经合并,复制回数组a
public void merge1(int[] a, int from, int mid, int end) {
//左右数组,且每个数组长度+1,为了存放哨兵值
int nl = mid - from + 1;
int nr = end - mid;
int[] left = new int[nl + 1];
int[] right = new int[nr + 1];
System.arraycopy(a, from, left, 0, nl);
System.arraycopy(a, mid+1, right, 0, nr);
//哨兵值
left[nl] = Integer.MAX_VALUE;
right[nr] = Integer.MAX_VALUE;
int i = 0; //控制左边数组
int j = 0; //控制右边数组
//从左右两个临时数组中各取一个数比较,将较小的一个数复制回数组
for (int k = from; k <= end; k++) {
if (left[i] <= right[j]) {
//哨兵值在这里得到体现,如果其中一个复制完,就会一直复制另外一个
a[k] = left[i];
i++; //接着下一个
} else {
a[k] = right[j];
j++;
}
}
}
//方法二:不使用哨兵值,一旦其中的一个子序列所有元素都被复制回数组a,就立刻停止
//再将另外一个子序列中剩余的元素复制回数组a即可
public void merge2(int[] a, int from, int mid, int end) {
//左右数组
int nl = mid - from + 1;
int nr = end - mid;
int[] left = new int[nl];
int[] right = new int[nr];
System.arraycopy(a, from, left, 0, nl);
System.arraycopy(a, mid+1, right, 0, nr);
int i=0, j=0, k=from;
//一旦其中一个子序列所有元素复制完就立刻停止
while(i < nl & j < nr) {
if(left[i] <= right[j]) {
a[k++] = left[i++];
} else {
a[k++] = right[j++];
}
}
//复制剩余的元素
for(; i < nl; i++){
a[k++] = left[i];
}
for(; j < nr; j++) {
a[k++] = right[j];
}
}
//递归划分数组
public void mergeSort(int[] a, int from, int end) {
//单个元素视为已排好序的
if(from < end) {
//从中间划分数组
int mid = (end + from) / 2;
//递归划分数组
mergeSort(a, from, mid);
mergeSort(a, mid+1, end);
merge2(a, from, mid, end);
}
}
//对整个数组排序
public void mergeSort(int[] a) {
mergeSort(a, 0, a.length-1);
}
//打印数组
public void printArr(String str, int[] a) {
System.out.print(str + "\t");
for(int i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
System.out.println();
}
//测试数据
public static void main(String[] args) {
MergeSort ms = new MergeSort();
int[] a = {1,4,3,7,5,8,0};
ms.printArr("原始数组为:", a);
ms.mergeSort(a);
ms.printArr("合并排序后:", a);
}
}
//output~
原始数组为: 1 4 3 7 5 8 0
合并排序后: 0 1 3 4 5 7 8