Java 归并排序算法

Posted 曾淘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 归并排序算法相关的知识,希望对你有一定的参考价值。

简介

上一章我们学习了 Java 快速排序算法,这一章,我们来学习快归并排序算法,so,多了不说,继续老规矩,学习内容如下:
1、归并排序的定义
2、归并排序的思路
3、代码实现
4、运行过程 & 代码分析

1、归并排序的定义

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

和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。

2、归并排序的思路

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

这里借助一个图 此图为借鉴,自己懒得画,如有侵权,请联系我处理! 作为说明:假设数组源为,84571362

3、代码实现

package com.gongchao.boss;

import java.util.Arrays;

/**
 * description: 归并排序方法
 * auth: zengtao
 * time: 2020-12-23 16:45
 **/
public class Main 

    public static void main(String[] args) 
        int array[] = 6, 5, 2, 7, 4, 3, 8, 12, 4, 9;
        // 归并排序方法
        System.out.println("排序前:" + Arrays.toString(array));
        mergeSoft(array, 0, array.length - 1);
        System.out.println("排序后:" + Arrays.toString(array));
    

    // 归并
    private static void mergeSoft(int[] arr, int low, int high) 
        int middle = (high + low) / 2;
        //递归,直到low==high,也就是数组已不能再分了,
        if (low < high) 
            // 左数组排序
            mergeSoft(arr, low, middle);
            // 右数组排序
            mergeSoft(arr, middle + 1, high);
            // 当数组不能再分,开始归并排序
            merge(arr, low, middle, high);
        
    

    /**
     * 合并数据
     *
     * @param arr    数组
     * @param low    开始位置
     * @param middle 中间位置
     * @param high   结束位置
     */
    private static void merge(int[] arr, int low, int middle, int high) 
        // 临时数组,用于存储arr数据
        int[] tempArr = new int[high - low + 1];
        // 第一个数组的开始下标
        int i = low;
        // 第二个数组的开始下标
        int j = middle + 1;
        // 临时数组的下标,默认为0开始
        int index = 0;

        // 比较两个数组中的数据,然后存储
        while (i <= middle && j <= high) 
            // 两个数组第一个数据比较,把小的数组放入数组中,临时数组下标和数组小/大的下标移动
            if (arr[i] <= arr[j]) 
                tempArr[index++] = arr[i++];
             else 
                tempArr[index++] = arr[j++];
            
        

        // 上面数据对比之后,数据1数据还有剩余
        // 数组1【6, 5, 2, 7, 4, 3, 8】,数组2【12, 4, 9】,那么,数组1数据>数组2数据,
        if (i <= middle) 
            // 只剩数组1数据,都是有序数据,所以数据直接放入临时数组
            tempArr[index++] = arr[i++];
        
        // 上面数据对比之后,数据2数据还有剩余
        // 数组1【6, 5, 2, 7】,数组2【4, 3, 8,12, 4, 9】,那么,数组1数据< 数组2数据,
        if (j <= high) 
            // 只剩数组2数据,都是有序数据,所以数据直接放入临时数组
            tempArr[index++] = arr[j++];
        

        System.out.println("    排序中:" + Arrays.toString(arr));

        // 重新临时数组中的数据,放入原数组中
        for (int k = 0; k < index; k++) 
            arr[k + low] = tempArr[k];
        
    

运行结果

根据运行结果:这样我们就是实现了归并排序

4、运行过程 & 代码分析

为什么要写这个呢?

之前有些同学私信我,有些局部代码看起来还是有些吃力,感觉自己便携代码有点抓不住。

所以,这个也是针对这些同学,我一点一点的说明,方便同学更加方便理解。

一:首先我们先按照排序的思路来看

把长度为n的输入序列分成两个长度为n/2的子序列;
对这两个子序列分别采用归并排序;

分析

  • 长度为n的输入序列------> 输入数组arr[]
  • 输入数组,分为长度为n/2的数组------> 第1⃣️个开始位置到结束,第2⃣️个开始位置(第一个结束位置)到整个数组结束
  • 对这两个子序列分别采用归并排序 -----> 方法中有归并,第1⃣️个归并,第2⃣️个归并

那么方法和参数就如约而来了,代码如下:

	// 归并
    private static void mergeSoft(int[] arr, int low, int high) 
        int middle = (high + low) / 2;
        //递归,直到low==high,也就是数组已不能再分了,
        if (low < high) 
            // 左数组排序
            mergeSoft(arr, low, middle);
            // 右数组排序
            mergeSoft(arr, middle + 1, high);
            // 当数组不能再分,开始归并排序
            merge(arr, low, middle, high);
        
    

二:其次我们看最后一个思路

将两个排序好的子序列,合并成一个最终的排序序列。

那么就会有一个最终的具体的合并排序方法,内部原理如下

  • 1.将数组分类2个,那么分别有2个,各自的start位置+结束位置
 private static void merge(int[] arr, int low, int middle, int high) 
 
 
  • 2.分别将2个数组对比,大数组的放在一边,小的数据放在一边
		// 临时数组,用于存储arr数据
        int[] tempArr = new int[high - low + 1];
        // 第一个数组的开始下标
        int i = low;
        // 第二个数组的开始下标
        int j = middle + 1;
        // 临时数组的下标,默认为0开始
        int index = 0;

        // 比较两个数组中的数据,然后存储
        while (i <= middle && j <= high) 
            // 两个数组第一个数据比较,把小的数组放入数组中,临时数组下标和数组小/大的下标移动
            if (arr[i] <= arr[j]) 
                tempArr[index++] = arr[i++];
             else 
                tempArr[index++] = arr[j++];
            
        
  • 3.若:数组1vs数组2,数组1数据多,那么继续处理数组1,此为有序排序,若:数组1vs数组2,数组2多,那么继续处理数组2
        // 上面数据对比之后,数据1数据还有剩余
        // 数组1【6, 5, 2, 7, 4, 3, 8】,数组2【12, 4, 9】,那么,数组1数据>数组2数据,
        if (i <= middle) 
            // 只剩数组1数据,都是有序数据,所以数据直接放入临时数组
            tempArr[index++] = arr[i++];
        
        // 上面数据对比之后,数据2数据还有剩余
        // 数组1【6, 5, 2, 7】,数组2【4, 3, 8,12, 4, 9】,那么,数组1数据< 数组2数据,
        if (j <= high) 
            // 只剩数组2数据,都是有序数据,所以数据直接放入临时数组
            tempArr[index++] = arr[j++];
        
  • 4.将最终数据返回给原数组
 // 重新临时数组中的数据,放入原数组中
        for (int k = 0; k < index; k++) 
            arr[k + low] = tempArr[k];
        

到此为止

代码具体解析,都已一一说明,希望对同学们有用。

谢谢观看,Thanks!

以上是关于Java 归并排序算法的主要内容,如果未能解决你的问题,请参考以下文章

常用排序算法及java示例

算法 | 分治 | 归并排序

排序算法--归并排序

排序算法之归并排序

算法学习归并排序

数据结构与算法笔记—— 归并排序