归并排序,首先需要用到递归,递归这个东西说难不难,说简单也挺烦的。
一、递归是什么
递归从代码直观的表现来看,就是自己调用自己。比如这样:
public int recursive(int a){ return a+recursive(a++); }
这样就是一个递归,但是问题是这样会无线递归下去。所以必须给他一个出口:
public static void main(String[] args) { System.out.println(recursive(0)); } public static int recursive(int a) { if (a > 10) return 0;//当a大于10的时候直接返回 return a + recursive(++a); }
这个递归就是个从1加到10的结果,重点不在递归,递归就到这里。
二、归并排序
什么是归并排序?首先我们假定这个数组可以分成两半,而且在这两个半个数组中是排好顺序的,然后将这两个数组合并。
package test; /** * <p></p> * * @author zy 刘会发 * @version 1.0 * @since 2020/4/14 */ public class MergeSort { public static void main(String[] args) { int[] a = new int[]{1, 3, 5, 7, 2, 4, 6}; sort(a); print(a); } public static void sort(int arr[]) { merge(arr); } public static void merge(int arr[]) { int mid = arr.length / 2 + 1;//数组的中间位置; int[] temp = new int[arr.length];//定一个中间数组 int i = 0;//左边数组开始的位置 int j = mid;//右边数组开始的位置 int k = 0;//新数组开始的位置 while (i < mid && j < arr.length) { if (arr[i] <= arr[j]) {//如果左边的小将左边的值放到新数组中 temp[k] = arr[i]; i++;//下标加一 } else { temp[k] = arr[j];//否者右边的放到新数组中 j++; } k++;//新数组下标加一 } //可能在上边的合并完后原数组中还有为合并的数值 while (i < mid) temp[k++] = arr[i++];//将左半个数组中数值复制到新数组中 while (j < arr.length) temp[k++] = arr[j++];//将右半个数组中数值复制到新数组中 for (int m = 0; m < temp.length; m++) {//将新的数组中的值复制到原数组中 arr[m] = temp[m]; } } public static void print(int arr[]) {//打印 for (int i = 0; i < arr.length; i++) { System.out.printf("%d,", arr[i]); } } }
上诉代码是假定两个半个数组中都已经排好顺序了,但是实际情况并不会是这种情况的,所以这样的代码一定是不可以的,还需要修改!
package test; /** * <p></p> * * @author zy 刘会发 * @version 1.0 * @since 2020/4/14 */ public class MergeSort { public static void main(String[] args) { int[] a = new int[]{1, 3, 5, 7, 2, 4, 6}; sort(a); print(a); } public static void sort(int arr[]) { merge(arr, 0, 4, arr.length); } /** * <p>因为合并可能会重任意一个位置开始,任意一个位置结束,所以需要指定几个参数<p/> * * @param arr 要排序的数组 * @param leftPro 左指针 包含 * @param rightPro 右指针 包含 * @param rightBound 右边界 不包含 */ public static void merge(int arr[], int leftPro, int rightPro, int rightBound) { int mid = rightPro - 1;//数组的中间位置; int[] temp = new int[rightBound - leftPro];//定一个中间数组 int i = leftPro;//左边数组开始的位置 int j = rightPro;//右边数组开始的位置 int k = 0;//新数组开始的位置 while (i <= mid && j < rightBound) { if (arr[i] <= arr[j]) {//如果左边的小将左边的值放到新数组中 temp[k] = arr[i]; i++;//下标加一 } else { temp[k] = arr[j];//否者右边的放到新数组中 j++; } k++;//新数组下标加一 } //可能在上边的合并完后原数组中还有为合并的数值 while (i <= mid) temp[k++] = arr[i++];//将左半个数组中数值复制到新数组中 while (j < rightBound) temp[k++] = arr[j++];//将右半个数组中数值复制到新数组中 for (int m = 0; m < temp.length; m++) {//将新的数组中的值复制到原数组中 arr[leftPro + m] = temp[m]; } } public static void print(int arr[]) {//打印 for (int i = 0; i < arr.length; i++) { System.out.printf("%d,", arr[i]); } } }
那么这样修改就灵活一些了,可以再数组任何位置进行合并了,既然是归并排序,那么接下来就是递归了。
package test; /** * <p></p> * * @author zy 刘会发 * @version 1.0 * @since 2020/4/14 */ public class MergeSort { public static void main(String[] args) { int[] a = new int[]{1, 3, 5, 7,2,4,6}; sort(a, 0, a.length-1); print(a); } /** * <p>对sort方法进行递归</p> * * @param arr 要排序的数组 * @param left 左边开始的位置 * @param right 右边结束的位置 */ public static void sort(int arr[], int left, int right) { if (left == right) return;//递归的出口,如果开始的位置和结束的位置相同,那么只有一个元素,直接返回即可 //首先将数组分成两个部分 int mid = (left + right) / 2; //先对左边的进行排序 sort(arr, left, mid); //然后对右边的进行排序 sort(arr, mid + 1, right); //合并两个排好顺序的数组 merge(arr, left, mid + 1, right); } /** * <p>因为合并可能会重任意一个位置开始,任意一个位置结束,所以需要指定几个参数<p/> * * @param arr 要排序的数组 * @param leftPro 左指针 包含 * @param rightPro 右指针 包含 * @param rightBound 右边界 不包含 */ public static void merge(int arr[], int leftPro, int rightPro, int rightBound) { int mid = rightPro - 1;//数组的中间位置; int[] temp = new int[rightBound - leftPro];//定一个中间数组 int i = leftPro;//左边数组开始的位置 int j = rightPro;//右边数组开始的位置 int k = 0;//新数组开始的位置 while (i <= mid && j <= rightBound) { if (arr[i] <= arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } //可能在上边的合并完后原数组中还有为合并的数值 while (i <= mid) temp[k++] = arr[i++];//将左半个数组中数值复制到新数组中 while (j <= rightBound) temp[k++] = arr[j++];//将右半个数组中数值复制到新数组中 for (int m = 0; m < temp.length; m++) {//将新的数组中的值复制到原数组中 arr[leftPro + m] = temp[m]; } } public static void print(int arr[]) {//打印 for (int i = 0; i < arr.length; i++) { System.out.printf("%d,", arr[i]); } } }