递归算法其实就是拆解+归并才是完整的,不能单看把两个有序数组归并,而是学会拆分,我……
递归算法里有个非常烧脑的……大概我脑子不好的递归理解
就是那个双层嵌套的sort递归,我实在无法理解,所以画了个图,来排{9084}这四个数
就是
一开始完全不理解这也能递归??画图后果然清晰多了
打印一共执行了三次原地归并,我却不知道怎么来的……所以……
private static void sort(Comparable[] a, int lo, int 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); System.out.println(Arrays.toString(a)); }
所以每一个return或者执行完一次归并就会跳出这层递归而不是单纯的循环执行。
理解这个算法首先要学会拆解,它的确实现了拆解,具体自行意会吧。
接下来上源码
package Chapter2_2.MergeSort; import java.util.Arrays; import Chapter2_1.ElementarySorts.Example; import Chapter2_1.ElementarySorts.Shell; import edu.princeton.cs.algs4.In; public class Merge extends Example { /* * 原地归并的抽象方法+自顶向下的归并排序 */ @SuppressWarnings("rawtypes") private static Comparable[] aux; /* * 原地归并的抽象方法 将(一个数组分割为两个)不同的两个有序数组归并到第三个数组中。 */ public static void merge(Comparable[] a, int lo, int mid, int hi) { int i = lo, j = mid + 1;// i是左边,j是右边 for (int k = lo; k <= hi; k++) { aux[k] = a[k];// 将a复制到aux里 } for (int k = lo; k <= hi; k++) {// 用左边左边要递增,用右边右边要递增 if (i > mid) { a[k] = aux[j++]; } // 左半边用尽取右半边的元素 else if (j > hi) { a[k] = aux[i++]; } // 右半边用尽取左半边的元素 else if (less(aux[j], aux[i])) {// 当前元素小于左边的当前元素则取右半边的元素 a[k] = aux[j++]; } else { a[k] = aux[i++]; } } } public static void sort(Comparable[] a) { aux = new Comparable[a.length];// 一次性分配空间 sort(a, 0, a.length - 1); } private static void sort(Comparable[] a, int lo, int 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); System.out.println(Arrays.toString(a)); } public static void main(String[] args) { String[] a = In.readStrings(); sort(a); assert isSorted(a); show(a); } }