归并排序(递归和非递归)的实现

(二分)归并排序,其实就是两两合并,保证每一组有序(开始时每组只有一个元素肯定有序),两组合并后保证有序。因为合并时有对比过程,分别将两组中较小的先放入合并组,两组中有一组没有元素后,另一组元素直接拿到合并组。最终合成的一个大组,即整个数组,也是有序的。

递归实现:

/**
     * 归并排序(递归)
     * @param array 待排序数组
     */
    private static void mergeSort(int[] array) {
        if (array==null || array.length<2) {
            return;
        }

        mergeSort(array, 0 , array.length-1);
    }

    /**
     * 根据边界归并排序边界内部分
     * @param array 待排序数组
     * @param l 左边界(含)
     * @param r 右边界(含)
     */
    private static void mergeSort(int[] array, int l, int r) {
        if (l >= r) return;

        // 中间位置不用 l+r/2 的原因是数组很大时,l+r会溢出
        int mid = l + ((r-l) >> 1);
        // 左部分排序
        mergeSort(array, l, mid);
        // 右部分排序
        mergeSort(array, mid+1, r);
        // 两个部分排序后的结果进行合并
        merge(array, l, mid, r);
    }

    /**
     * 两个排序好的部分进行合并成一个有序部分
     * @param array 数组
     * @param l 左边界(含)
     * @param mid 中间位置角标
     * @param r 右边界(含)
     */
    private static void merge(int[] array, int l, int mid, int r) {
        int[] help = new int[r-l+1];
        int index = 0;
        int leftCursor = l;
        int rightCursor = mid+1;
        /*游标在两部分都未越界*/
        while (leftCursor <= mid && rightCursor<=r) {
            if (array[leftCursor] < array[rightCursor]) {
                help[index++] = array[leftCursor++];
            } else if (array[leftCursor] > array[rightCursor]) {
                help[index++] = array[rightCursor++];
            } else {
                help[index++] = array[leftCursor++];
                help[index++] = array[rightCursor++];
            }
        }

        /*右部分越界,左部分剩余的值直接拿过来*/
        while (leftCursor <= mid) {
            help[index++] = array[leftCursor++];
        }

        /*左部分越界,右部分剩余的直接拿过来*/
        while (rightCursor <= r) {
            help[index++] = array[rightCursor++];
        }

        /*辅助数组替换原有数组*/
        index=0;
        while (l <= r) {
            array[l++] = help[index++];
        }
    }

非递归实现:
 

/**
     * 归并排序(非递归)
     * @param array 待排序数组
     */
    private static void mergeSortV2(int[] array){
        if (array==null || array.length<2) {
            return;
        }

        int length = array.length;
        int groupSize = 1;// 分组大小
        /*分组大小大于或等于就不用排序合并了*/
        while (groupSize < length) {
            int groupNum = length/groupSize;// 判断可以分多少组。需要注意可能后面还有不够一组的部分
            boolean moreGroup = length % groupSize > 0;// 是否还有不够一组的
            int l = 0;
            for (int i = 0; i < groupNum; i+=2) {
                int mid = l + groupSize - 1, r = mid + groupSize;// 左右边界
                if (r > length-1) {
                    if (! moreGroup) {
                        break;
                    } else {
                        r = length-1;
                    }
                }
                merge(array, l, mid, r);
                l = r + 1;
            }


            /*为防止groupSize溢出,需要做个判断*/
            if (groupSize > (length >> 1)) {
                break;
            } else {
                groupSize <<= 1;
            }
        }
    }

非递归排序的难点:需要控制数组的边界,分组大小的边界。

两种递归和非递归的实现对比,从中可以发现,这两种代码其实做的是一件事,归并排序执行的顺序是一样的,但是思考的过程是相反的。

猜你喜欢

转载自blog.csdn.net/u011471105/article/details/119617510