Java归并排序

归并排序采用分治思想,通过递归将数组拆分成小部分并分别排序,再合并成有序数组。递归出口是数组长度为1,表示绝对有序。首次合并发生在数组拆分为两个长度为1的子数组时,之后不断合并成更长的有序数组,最终完成排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是归并排序

归并排序的核心思想还是蛮简单的。如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。归并排序使用的就是分治思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的子问题来解决。小的子问题解决了,大问题也就解决了。分治算法一般都是用递归来实现的。分治是一种解决问题的处理思想,递归(传递—>回归)是一种编程技巧,这两者并不冲突。
归并算法图解

从编码的角度分析归并排序

刚开始接触归并排序的时候,可能会有这么一个疑惑。利用递归的方式将大数组不断拆分成小数组,然后将小数组合并起来,最后就能实现排序呢?这里不要去想递归的整个过程,更不要想去搞清递归的每一次执行结果。这样会陷入一个思维误区,人的思维方式和计算机处理问题的方式是不一样的。
这里说明一下几个思考点:

  • 递归出口不只是意味递归到此结束,还说明数组被拆分到最小数组时的数组长度为1,对于一个数来说它是绝对有序的!
  • 什么时候第一次数组合并?当然是数组被拆分到最小数组(长度为1)时合并,此时左边的有序数组长度为1右边的数组长度为1。我们只需要将小的数放在前面即可,最后就是一个长度为2的有序数组
  • 以此类推,递归算法从传递(拆分数组)到回归(合并有序数组)
package com.learn.algo;

import java.util.Arrays;

public class Sort {
    public static void main(String[] args) {
        int[] numbers = new int[] {1,2,3,1,2,5,14,21,11,20,95,100,8,9};
        System.out.println(Arrays.toString(numbers));
        mergeSort(numbers,0,numbers.length - 1);
        System.out.println(Arrays.toString(numbers));
    }

    /**
     * 归并排序
     * @param numbers 待排序数组
     * @param startIndex
     * @param endIndex
     */
    public static void mergeSort(int[] numbers, int startIndex, int endIndex) {
        //递归出口
        if (startIndex >= endIndex) return;
        //计算数组的中间元素下标
        int middleIndex = (endIndex + startIndex) / 2;
        //对左边进行排序
        mergeSort(numbers, startIndex, middleIndex);
        //对右边进行排序
        mergeSort(numbers, middleIndex + 1, endIndex);
        //合并左右有序数组
        merge(numbers, startIndex, middleIndex, endIndex);
    }

    /**
     * 合并两个有序数组
     * @param numbers
     * @param startIndex
     * @param middleIndex
     * @param endIndex
     */
    private static void merge(int numbers[], int startIndex, int middleIndex, int endIndex) {
        //定义一个缓存数组
        int[] buffer = new int[endIndex - startIndex + 1];

        //从左边开始比较,左边的小于等于右边的就排在前面,这样原有数组中元素大小的相对位置不会改变,该算法就为稳定的排序算法
        //左边有序数组number[startIndex]->number[middleIndex]
        //右边有序数组number[middleIndex + 1]->number[endIndex]
        //while中的条件是为了保证左边或右边的有序数组至少有一个遍历完
        int l = startIndex, r = middleIndex + 1, i = 0;
        while (l <= middleIndex && r <= endIndex) {
            if (numbers[l] <= numbers[r]) {
                buffer[i++] = numbers[l++];
            } else {
                buffer[i++] = numbers[r++];
            }
        }

        //如果左边的有序数组未遍历完则直接提取出左边的元素
        while (l <= middleIndex) {
            buffer[i++] = numbers[l++];
        }

        //如果右边的有序数组未遍历完则直接提取出左边的元素
        while (r <= endIndex) {
            buffer[i++] = numbers[r++];
        }

        //赋值给原始数组
        System.arraycopy(buffer, 0, numbers, startIndex, buffer.length);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值