归并排序算法原理及实现

6.8 归并排序

6.8.1归并排序介绍

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

6.8.2 基本思想

对于一个待排序的数组,首先进行分解,将整个待排序数组以mid中间位置为界,一分为二,随后接着分割,直至到最小单位无法分割;开始进行治的操作,将每两个小部分进行比较排序,并逐步合并;直至合并成整个数组的大小。从而完成了整个排序的过程。

以数据{8,4,5,7,1,3,6,2}为例,归并排序思想的示意图如下:

  • 首先是分的步骤,将整个数组进行分割,分成了若干个单独的较小的单元。
    在这里插入图片描述

  • 然后是合并的过程,分别将分开的两个较小单元进行比较合并到原来的数组里面;将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],步骤如下图所示:

在这里插入图片描述

6.8.3 代码实现
package com.kevin.sortAlgorithm;

import java.util.Arrays;

/**
 * @author : kevin ding
 * @date : 2022/3/10 22:20
 * @description :   归并排序 采用经典的分治策略,先将问题分解成一些笑的问题,然后递归求解
 */
public class MergeSortDemo {
    
    
    public static void main(String[] args) {
    
    
        int[] array = {
    
    8,4,5,7,1,3,6,2};
        int[] tempArray = new int[array.length];
        System.out.println("merge排序之前:");
        System.out.println(Arrays.toString(array));

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

        System.out.println("merge排序之后:");
        System.out.println(Arrays.toString(array));
    }

    public static void mergeSort(int[] array, int left, int right, int[] tempArray){
    
    
        // 先开始分,在合并。分之前 必须保证left < right才能分
        if(left < right){
    
    
            // 分之前 先先求解中间值
            int mid = (left + right) / 2;
            // 向左 接着分,以left为左边界,以mid为右边界
            mergeSort(array, left, mid, tempArray);
            // 向右接着分 以mid+1为左边界,right为右边界
            mergeSort(array, mid+1, right, tempArray);
            // 分完之后,开始合并
            merge(array, left, mid, right, tempArray);
        }
    }

    /**
     *
     * @param array     待排序的数组
     * @param left      待排序数组的左边界
     * @param mid       待排序数组的中间值 (左右两个有序序列的界限)
     * @param right     待排序数组的右边界
     * @param tempArray 临时数组,存放部分排序好的数据
     */
    public static void merge(int[] array, int left, int mid, int right, int[] tempArray){
    
    
        int leftIndex = left;   // 左边有序数组的索引
        int rightIndex = mid+1; // 右边有序数组的索引
        int tempIndex = 0;  // 定义临时数组的索引

        // 1. 将左右两边有序数组中的数,按照大小依次放入的tempArray中,直到其中一个有序数组放入完毕
        // 左边有序数组的右边界为mid,右边数组的右边界为right,只要任一索引到边界,则遍历结束
        while (leftIndex <= mid && rightIndex <= right){
    
    
            if(array[leftIndex] <= array[rightIndex]){
    
    
                // 左边序列的当前值小,将其存入tempArray中,随后将索引分别后移一位
                tempArray[tempIndex] = array[leftIndex];
                tempIndex += 1;
                leftIndex += 1;
            }else{
    
    
                // 否则,右边序列的当前值较小,存入tempArray中
                tempArray[tempIndex] = array[rightIndex];
                tempIndex += 1;
                rightIndex += 1;
            }
        }

        // 2. 将剩余一个有序数组的值全部依次放入到临时数组tempArray中
        // 左边有序数组还有剩余
        while(leftIndex <= mid){
    
    
            tempArray[tempIndex] = array[leftIndex];
            tempIndex += 1;
            leftIndex += 1;
        }
        // 右边有序数组还有剩余
        while(rightIndex <= right){
    
    

            tempArray[tempIndex] = array[rightIndex];
            tempIndex += 1;
            rightIndex += 1;
        }
        // 3.将临时数组中已排好序的值,再拷贝回原数组中
        // 拷贝回去时,tempIndex每次都是从零开始,因为每次合并的时候都是从零位置开始往里放
        tempIndex = 0;
        // 往回拷贝,并非每次都是拷贝所有,是根据传入的参数left和right来定的
        int tempLeftIndex = left;
        // 开始拷贝,从left到right
        while(tempLeftIndex <= right){
    
    
            array[tempLeftIndex] = tempArray[tempIndex];
            tempLeftIndex += 1;
            tempIndex += 1;
        }

    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43155804/article/details/123435534