归并排序(merge sort)Java版 非递归实现

归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

  1. 自上而下的递归
  2. 自下而上的迭代(本文是非递归方式)
1. 算法原理

分治思想
归并排序是一个分治算法(Divide and Conquer)的一个典型实例,归并排序有多路归并排序、两路归并排序
排序思想:
1. 分解待排序的n个元素为两个子列,各为n/2个元素
2. 若子列没有排好序,重复1步骤,每个子列继续分解为两个子列,直至被分解的子列个数为1
3. 子列元素个数为1,说明这个子列已经排好序,开始逐级合并子序列进行排序
比较合并

2. 算法动图演示

动图演示

3. 代码实现
/**
 * @ClassName: MergeSort
 * @Description:
 * @Author: tp.cheng
 * @Date: 2020/8/20 15:41
 * @Version V1.0
 **/
import java.util.Arrays;

/**
 * 归并排序是一个分治算法(Divide and Conquer)的一个典型实例,归并排序有多路归并排序、两路归并排序
 * 排序思想:
 * 1,分解待排序的n个元素为两个子列,各为n/2个元素
 * 2,若子列没有排好序,重复1步骤,每个子列继续分解为两个子列,直至被分解的子列个数为1
 * 3,子列元素个数为1,说明这个子列已经排好序,开始逐级合并子序列进行排序
 */
public class MergeSort {
    public static void main(String[] args) {
        int[] input = {4, 7, 5, 1, 6, 3, 2, 8};
        sort(input);
        System.out.println(Arrays.toString(input));
    }

    /**
     * 归并排序(非递归实现)
     * 时间复杂度O(nlogn)
     * 空间复杂度O(n)
     */
    private static void sort(int[] arr) {
        // 非递归实现,拆分的方式可以理解为:完全二叉树的分层遍历
        // 从 1 开始分割,与递归不同的是,递归由数组长度一分为二最后到1,
        // 而非递归则是从1开始扩大二倍直到数组长度

        int start = 1;
        // 排序前先创建一个和原始数组等长的临时数组,避免在拆分过程中频繁开辟空间
        int[] tempArr = new int[arr.length];
        // 步进从2->4->8直到数组长度,
        while (start < arr.length) {
            for (int i = 0; i + start < arr.length; i += start << 1) {
                int left = i;
                int mid = i + start - 1;
                int right = i + (start << 1) - 1;

                // 防止最后超过数组长度
                if (right > arr.length - 1) {
                    right = arr.length - 1;
                }
                merge(arr, tempArr, left, mid, right);
            }
            start <<= 1;
        }
    }
    
    private static void merge(int[] arr, int[] tempArr, int left, int mid, int right) {
        int i = left;//左序列指针
        int j = mid + 1;//右序列指针
        int k = left;//临时数组指针

        // 注意: 此处并没有全部放入temp中,当一边达到mid或right时就是退出循环
        while (i <= mid && j <= right) {
            if (arr[i] < arr[j]) {
                // 降序排序,如果是升序,改为arr[i++]即可
                tempArr[k++] = arr[j++];
            } else {
                tempArr[k++] = arr[i++];
            }
        }

        while (i <= mid) {
            tempArr[k++] = arr[i++];
        }

        while (j <= right) {
            tempArr[k++] = arr[j++];
        }

        while (left <= right) {
            arr[left] = tempArr[left++];
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值