归并排序

归并排序

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

算法描述

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

动画演示:

在这里插入图片描述

需求:

排序前:{8,4,5,7,1,3,6,2}
排序后:{1,2,3,4,5,6,7,8}
在这里插入图片描述

排序原理:

1、尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。
2、将相邻的两个子组进行合并成一个有序的大组;
3、不断的重复步骤2,直到最终只有一个组为止。

方法介绍:

1、sort(int[] arr)
  • 传入排序数组
  • 初始化辅助数组
  • 定义最大,最小索引值
  • 递归调用重载方法
 private static void sort(int[] arr){
       //1、初始化辅助数组assist;
       assist = new int[arr.length];
       //2、定义一个minIndex变量和maxIndex变量,分别记录数组中最小的索引和最大的索引
       int minIndex = 0;
       int maxIndex = arr.length-1;
       //3、调用sort重载方法完成数组a中,从索引minIndex到索引maxIndex的元素的排序
       sort(arr, minIndex,  maxIndex);
   }
2、sort(int[] arr, int minIndex, int maxIndex)
  • sort[int[] arr] 的重载方法,也是真正的排序方法
  • 分组
  • 对每一组进行排序
  • 归并
private static void sort(int[] arr, int minIndex,  int maxIndex){
       //做安全性校验
       if(minIndex>=maxIndex){
           return;
       }
       //对minIndex到maxIndex之间的数据进行2个分组
       int midIndex = minIndex+(maxIndex-minIndex)/2;
       //分别对每一组数据进行排序
       sort(arr,minIndex,midIndex);
       sort(arr,midIndex+1,maxIndex);
       //再把两个组中的数据进行归并
       merge(arr,  minIndex,  midIndex,  maxIndex);
   }
3、merge(int[] arr, int minIndex, int midIndex, int maxIndex)
  • 归并(算法的核心部分)
 private static void merge(int[] arr, int minIndex, int midIndex, int maxIndex){
       //定义三个指针
       int i = minIndex;
       int p1 = minIndex;
       int p2 = midIndex+1;
       //遍历,移动p1,p2指针,比较对应位置索引处的值,找出小的那个,放到辅助数组的对应处索引
       while(p1<=midIndex && p2<=maxIndex){
           //比较对应索引处的值
           if(arr[p1]<arr[p2]){
               assist[i++] = arr[p1++];
           }else {
               assist[i++] = arr[p2++];
           }

       }
       //如果p1的指针没有走完,那么顺序移动p1指针,把对应的元素放在辅助数组的对应索引处
       while (p1<=midIndex){
           assist[i++] = arr[p1++];
       }
       //如果p2的指针没有走完,那么顺序移动p2指针,把对应的元素放在辅助数组的对应索引处
       while (p2<=maxIndex){
           assist[i++] = arr[p2++];
       }
       //把辅助数组中的元素copy到元素组中
       for (int j = minIndex;j<=maxIndex;j++){
           arr[j] = assist[j];
       }
   }
前提:
sort(int[] arr, int minIndex,  int maxIndex)被执行

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图片转自黑马程序员

完整java代码:

public class MergeSort {
    //辅助数组
    private static int[] assist;
    public static void main(String[] args) {
        int[] arr = {5,1,2,7,6,3,4,8};
        sort(arr);
        System.out.println(Arrays.toString(arr));

    }
    /*
    对数组a中的元素进行排序
     */
    private static void sort(int[] arr){
        //1、初始化辅助数组assist;
        assist = new int[arr.length];
        //2、定义一个minIndex变量和maxIndex变量,分别记录数组中最小的索引和最大的索引
        int minIndex = 0;
        int maxIndex = arr.length-1;
        //3、调用sort重载方法完成数组a中,从索引minIndex到索引maxIndex的元素的排序
        sort(arr, minIndex,  maxIndex);
    }
    /*
    对数组a中从minIndex到maxIndex元素进行排序
     */
    private static void sort(int[] arr, int minIndex,  int maxIndex){
        //做安全性校验
        if(minIndex>=maxIndex){
            return;
        }
        //对minIndex到maxIndex之间的数据进行2个分组
        int midIndex = minIndex+(maxIndex-minIndex)/2;
        //分别对每一组数据进行排序
        sort(arr,minIndex,midIndex);
        sort(arr,midIndex+1,maxIndex);
        //再把两个组中的数据进行归并
        merge(arr,  minIndex,  midIndex,  maxIndex);
    }
    /*
    对数组中minIndex到midIndex为一组,midIndex+1到maxIndex为一组,对两组数据进行归并
     */
    private static void merge(int[] arr, int minIndex, int midIndex, int maxIndex){
        //定义三个指针
        int i = minIndex;
        int p1 = minIndex;
        int p2 = midIndex+1;
        //遍历,移动p1,p2指针,比较对应位置索引处的值,找出小的那个,放到辅助数组的对应处索引
        while(p1<=midIndex && p2<=maxIndex){
            //比较对应索引处的值
            if(arr[p1]<arr[p2]){
                assist[i++] = arr[p1++];
            }else {
                assist[i++] = arr[p2++];
            }

        }
        //如果p1的指针没有走完,那么顺序移动p1指针,把对应的元素放在辅助数组的对应索引处
        while (p1<=midIndex){
            assist[i++] = arr[p1++];
        }
        //如果p2的指针没有走完,那么顺序移动p2指针,把对应的元素放在辅助数组的对应索引处
        while (p2<=maxIndex){
            assist[i++] = arr[p2++];
        }
        //把辅助数组中的元素copy到元素组中
        for (int j = minIndex;j<=maxIndex;j++){
            arr[j] = assist[j];
        }
    }
}

算法分析

归并排序时间复杂度分析:

归并排序是分治思想的最典型的例子,是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多

上面的算法中,对arr[minIndex…maxIndex]进行排序,先将它分为arr[minIndex…midIndex]和a[midIndex+1…maxIndex]两部分,分别通过递归调用将他们单独排序,最后将有序的子数组归并为最终的排序结果。该递归的出口在于如果一个数组不能再被分为两个子数组,那么就会执行merge进行归并,在归并的时候判断元素的大小进行排序。

终归并排序的时间复杂度为O(nlogn);

希尔排序和归并排序在处理大批量数据时差别不是很大

归并排序的缺点:

需要申请额外的数组空间,导致空间复杂度提升,是典型的以空间换时间的操作。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值