五、归并排序

归并排序,首先需要用到递归,递归这个东西说难不难,说简单也挺烦的。

一、递归是什么

递归从代码直观的表现来看,就是自己调用自己。比如这样:

 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]);
        }
    }
}

 

posted @ 2020-04-14 14:29  葬月!  阅读(134)  评论(0编辑  收藏  举报