归并排序——递归实现

 
 

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并

        基本思路:
        先递归的把数组划分为两个子数组,一直递归到数组中只有一个元素,然后再调用函数把两个子数组排好序,因为该函数在递归划分数组时会被压入栈,所以这个函数真正的作用是对两个有序的子数组进行排序;
        基本步骤:
        1、判断参数的有效性,也就是递归的出口;
        2、首先什么都不管,直接把数组平分成两个子数组;
        3、递归调用划分数组函数,最后划分到数组中只有一个元素,这也意味着数组是有序的了;
        4、然后调用排序函数,把两个有序的数组合并成一个有序的数组;
        5、排序函数的步骤,让两个数组的元素进行比较,把大的/小的元素存放到临时数组中,如果有一个数组的元素被取光了,那就直接把另一数组的元素放到临时数组中,然后把临时数组中的元素都复制到实际的数组中;
/**
 * 此递归排序的merge,并不是将数组a,b合并成c
 * 而是在原数组上,将下标left~mid与mid+1~right的两个数据段(相当于两个数组)合并成一个有序数组,再拷贝到原数组的对应位置,这都是在对原数组操作
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] arr = {9,8,7,6,5,4,3,2,1};
        mergeSort(arr);
        for (int i = 0;i<arr.length;i++){
            System.out.println(arr[i]);
        }

    }

    public void mergeSort(int[] arr){
        sort(arr,0,arr.length-1);
    }


    public static void sort(int[] arr,int left,int right){
        if (left < right){
            int mid = (left+right)/2;
            //先递归排序左边
            sort(arr,left,mid);
            //再递归排序右边
            sort(arr,mid+1,right);
            //合并两边排序后结果
            merge(arr,left,mid,right);
        }
    }

    /**
     * @desc 将同一个数组中的两段连续数据排序,前提,两段数据已经有序(从小到达)
     * 例如:1,3,5,7,9,2,4,6,8,
     * 从下标0到7排序后,1,2,3,4,5,6,7,8
     * 从下标3,6排序后,1,3,5,2,4,7,9,6,8
     * @param arr
     * @param left
     * @param mid
     * @param right
     * @return
     */
    public static void merge(int[] arr,int left,int mid,int right){
        //将两小段合并后的有序数组
        int[] r = new int[right-left+1];
        //r中的下标
        int k = 0;
        //第一段数组从left开始
        int i = left;
        //第二段数组从right开始
        int j = mid + 1;
        //循环条件:第一段数组和第二段数组下标都不超过各自的最后一个元素下标
        while (i <= mid && j <= right){
            if (arr[i] <= arr[j]){
                r[k++] = arr[i++];
            }else {
                r[k++] = arr[j++];
            }
        }
        //当两端数组的长度不想等时,可能存在其中一组还未被遍历到的情况,直接将其拷贝进r即可
        while (i <= mid){
            r[k++] = arr[i++];
        }
        //当两端数组的长度不想等时,可能存在其中一组还未被遍历到的情况,直接将其拷贝进r即可
        while (j <= right){
            r[k++] = arr[j++];
        }
        k = 0;
        //将已排好序的部分覆盖掉原数组的对应部分
        while (left <= right){
            arr[left++] = r[k++];
        }
    }

}

参考:https://www.cnblogs.com/chengxiao/p/6194356.html

归并排序是一种比较占内存,但却高效且稳定的算法。

时间复杂度:O(nlogn)

空间复杂度:O(n+logn),logn来自递归时额外的栈空间



猜你喜欢

转载自blog.csdn.net/xybz1993/article/details/80293461