自顶向下的归并排序
在本节中我们所讨论的算法都基于归并排序这个简单的操作,即将两个有序的数组归并排序成一个有序数组.很快人们就根据这个操作发明了一种简单的归并算法.要将一个数组排序,可以先将它分成两半分别排序,然后将结果归并起来.你将会看到,归并排序吸引人的性质是它能够保证将任意长度为N的数组排序所用的时间和NlogN成正比,它的主要缺点是所利用的额外空间和N成正比.
代码格式如下:
public class Merge {
private static int[] aux;
public static void main(String[] args) {
int[] A = { 2, 4, 1, 23, 54, 12, 65, 121, 45, 12, 44 };
aux = new int[A.length];
sort(A, 0,A.length-1);
show(A);
}
public static void sort(int[] A, int lo, int hi) {
//将数组A[lo...hi]排序
if (hi <= lo)
return;
int mid = lo + (hi - lo) / 2;
sort(A, lo, mid);
sort(A, mid + 1, hi);//思想
merge(A, lo, mid, hi);
}
public static void merge(int[] A, int lo, int mid, int hi) {
// 将上下两部分归并
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++) {
aux[k] = A[k];
}
for (int k = lo; k <= hi; k++) {
if (i > mid)
A[k] = aux[j++];
else if (j > hi)
A[k] = aux[i++];
else if (aux[j] < aux[i])
A[k] = aux[j++];
else
A[k] = aux[i++];
}
}
public static void show(int[] A) {
for(int i=0; i<A.length; i++)
{
System.out.print(A[i]+" ");
}
}
}
自顶向下的归并排序,先将它们细分到很小的部分,然后层层回溯,单独排序然后将有序的子数组归并成有序的数组.
要理解该排序就需要单独理解它的动态情况.
自底向上的归并排序
import java.lang.Math;
public class MergeBu {
private static int[]aux;
public static void main(String[] args) {
int[] A = { 21, 34, 24, 43, 654, 0, 67, 2, 5, 2, 4, 423, 5, 36, 45, 62, 435, 4634, 524, 324, 5434212, 1 };
aux = new int[A.length];
for (int sz = 1; sz < A.length; sz *= 2) {//子数组大小1,2,4,8...
for (int lo = 0; lo+sz < A.length; lo += 2 * sz) {
merge(A, lo, lo + sz - 1, Math.min(lo + 2 * sz - 1, A.length - 1));
}
}
show(A);
}
public static void show(int []A){
for (int i = 0; i < A.length; i++) {
System.out.print(A[i]+" ");
}
}
public static void merge(int[] A, int lo, int mid, int hi) {
int m=lo,n=mid+1;
for (int i = lo; i <= hi; i++) {
aux[i] = A[i];
}
for (int i = lo; i <=hi; i++) {
if (m > mid)
A[i] = aux[n++];
else if (n > hi)
A[i] = aux[m++];
else if (aux[m] > aux[n])
A[i] = aux[n++];
else
A[i] = aux[m++];
}
}
}
自底向上的归并排序会多次遍历整个数组,根据子数组的大小进行两两归并,子数组的大小sz的初始值为1,每次加倍,最后一个子数组的大小只有在数组大小是sz的偶数倍的时候才会等于sz(否则会比sz小).