排序算法之归并排序

归并排序介绍

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer )策略,分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之

将两个的有序数列合并成一个有序数列,称之为"归并"

归并排序基本思想

(1)分(分解):一开始对当前数组一分为二,并求出当前数组的中间索引 int middleIndex = (startIndex + endIndex) / 2;

(2)求解:递归地对两个子数组array[startIndex ...middleIndex ]、array[middleIndex +1...endIndex]进行归并排序,递归的结束条件是子数组的长度为1

(3)治(合并):将已排序的两个子数组array[startIndex ...middleIndex ]、array[middleIndex +1...endIndex]合并为一个有序的子数组array[startIndex ...endIndex]

归并排序图解过程

将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终有序序列[1,2,3,4,5,6,7,8],步骤 如下

 

代码实现

package com.zzb.sort;

import java.util.Arrays;

/**
 * @Auther: Administrator
 * @Date: 2020/3/10 12:41
 * @Description: 归并排序
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] array = {8, 4, 5, 7, 1, 3, 6, 2};

        // 每次合并时,存放有序序列的临时数组
        int[] tempArray = new int[array.length];
        mergeSort(array, 0, array.length - 1, tempArray);
        System.out.println(Arrays.toString(array));
        /*[1, 2, 3, 4, 5, 6, 7, 8]*/
    }

    /**
     * 归并排序算法(题外话:整个算法类似于二叉树的节点的后序遍历操作)
     * @param array 将要被拆分的数组
     * @param startIndex 将要被拆分数组的头部索引
     * @param endIndex 将要被拆分数组的尾部索引
     * @param tempArray 每次合并时,存放有序序列的临时数组
     */
    private static void mergeSort(int[] array, int startIndex, int endIndex, int[] tempArray) {
        // 对数组进行递归拆分,直到每一个子数组中只有一个元素时递归拆分结束
        if(startIndex < endIndex) {
            // 被拆分数组的中间索引
            int middleIndex = (startIndex + endIndex) / 2;
            // 左递归拆分数组(题外话:整个算法类似于二叉树的节点的后序遍历操作)
            mergeSort(array, startIndex, middleIndex, tempArray);
            // 右递归拆分数组(题外话:整个算法类似于二叉树的节点的后序遍历操作)
            mergeSort(array, middleIndex + 1, endIndex, tempArray);
            // 合并排序
            merge(array, startIndex, middleIndex, endIndex, tempArray);
        }
    }

    /**
     * 归并排序算法 合并两个有序序列为一个有序序列(题外话:整个算法类似于二叉树的节点的后序遍历操作)
     * @param array 被拆分后的待排序数组
     * @param startIndex 被拆分后的待排序数组的头部索引
     * @param middleIndex 被拆分后的待排序数组的中间索引
     * @param endIndex 被拆分后的待排序数组的尾部索引
     * @param tempArray 每次合并时,存放有序序列的临时数组
     */
    private static void merge(int[] array, int startIndex, int middleIndex, int endIndex, int[] tempArray) {
        // startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,左边子数组的开始索引
        // 初始值为startIndex
        int left = startIndex;
       // startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,左边子数组的结束索引
        int right = middleIndex;
        // startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,右边子数组的开始索引
        // 初始值为middleIndex+1
        int l = middleIndex+1;
       // startIndex 至 endIndex(包括startIndex与endIndex)索引之间的元素被拆分为两个子数组后,右边子数组的结束索引
        int r = endIndex;
        // 临时数组tempArray初始值
        int tempArrayIndex = 0;
        // 左右子数组中的元素比较大小进行排序
        while(left <= right && l <= r) {
            if(array[left] < array[l]) {
                tempArray[tempArrayIndex] = array[left];
                left ++;
                tempArrayIndex ++;
            }
            if(array[left] > array[l]) {
                tempArray[tempArrayIndex] = array[l];
                l ++;
                tempArrayIndex ++;
            }
        }
        // 存在左边子数组或者右边子数组有剩余元素的可能
        while(left <= right) {
            tempArray[tempArrayIndex] = array[left];
            left ++;
            tempArrayIndex ++;
        }
        while(l <= r) {
            tempArray[tempArrayIndex] = array[l];
            l ++;
            tempArrayIndex ++;
        }
        // 把临时数组tempArray已排序好的元素复制到原数组array中的相应索引位置
        tempArrayIndex = 0;
        while(startIndex <= endIndex) {
            array[startIndex] = tempArray[tempArrayIndex];
            startIndex ++;
            tempArrayIndex ++;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值