数据结构与算法(16):归并排序:及其相关的用例

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

在这里插入图片描述
分得过程中,将每个元素拆分出来,通过合并,将其排序,最核心的部分在于治.

在这里插入图片描述解释上图操作(这里将的是治这个阶段,讲解下最后一次合并):

  1. 定义了一个i,j分别指向两个有序的子序列的最前面,将i,j指向的数据做比较,将最小的那个数据指向temp数组,也就是临时数组
  2. 如果上述中是i最小,第二次就将i右移一次.假如说是j最小,同样的将j右移.这样就能比较第二次了
  3. 第二次继续比较i,j指向的数,如上图所示.
  4. 从上图中我们可以看到j已经指向了最后了,不能再继续右移了,那我们就将i指向的后面所有的数据直接复制到临时数组中
  5. 最后在临时数组中的数据复制到原来的数组

代码演示:

package com.qiu.sort;

import java.util.Arrays;

public class MergeSort {
    public static void main(String[] args) {
        int[] arr ={8,4,5,7,1,3,6,2};
        //归并排序需要有一个额外的空间
        int temp[] = new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("排序后的数组为:"+ Arrays.toString(arr));

    }
    //分+合并的方法
    public static void mergeSort(int[] arr,int left, int right,int[] temp){
       if (left < right){
           //中间索引
           int mid = (left + right) / 2;
           //向左递归进行分解
           mergeSort(arr,left,mid,temp);
           //向右递归进行分解
           mergeSort(arr,mid+1,right,temp);
            //到合并
           merge(arr,left,mid,right,temp);


       }
    }
    //合并的方法

    /**
     *
     * @param arr 排序的原始数组
     * @param left 左边有序的初始索引
     * @param mid 中间的索引
     * @param right 右边有序的索引
     * @param temp 做中转的数组
     */
    public static void merge(int[] arr,int left,int mid,int right,int[] temp){
        //初始化i,左边有序序列的初始索引
        int i = left;
        //初始化j,右边有序序列的初始索引
        int j = mid+1;
        //指向temp数组的当前索引
        int t = 0;

        //1.先把左右两边的数据,按规则填充到temp数组中去,直到左右两边的有序序列,有一方处理完毕,为止
        while (i <= mid && j <= right){
            //如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
            //即将左边的元素拷贝到temp数组中去,同时将t和i后移
            if (arr[i] <= arr[j]){
                temp[t] = arr[i];
                t += 1;
                i += 1;
            }else {
                //反之,将右边有序的当前元素填充到temp数组中
                temp[t] = arr[j];
                t += 1;
                j += 1;
            }
        }
        //2.将有剩余数据的一方,直接整块填充到temp中去
            while(i <= mid){
                //左边的有序序列还有剩余的元素,就全部填充到temp中去
                temp[t] = arr[i];
                t += 1;
                i += 1;
            }
        while(j <= right){
            //右边的有序序列还有剩余的元素,就全部填充到temp中去
            temp[t] = arr[j];
            t += 1;
            j += 1;
        }


        //3.将填充好了的temp数组的元素拷贝到array中去
        //注意并不是每次都考虑所有的

        t = 0;
        int tempLeft = left;
        while(tempLeft <= right){
            //第一次合并时tempLeft是为0的,right是1
            //第二次合并时tempLeft是为2的,right是3
            //第三次合并时tempLeft是为0的,right是3
            //最后一次templeft=0,right为数组的长度-1
            arr[tempLeft] = temp[t];
            t += 1;
            tempLeft += 1;
        }
    }
}

代码结果:
在这里插入图片描述
接下来就是运行多个数据进行时间测试:

代码:

 public static void main(String[] args) {
//        int[] arr ={8,4,5,7,1,3,6,2,9};
//        //归并排序需要有一个额外的空间
//        int temp[] = new int[arr.length];
//        mergeSort(arr,0,arr.length-1,temp);
//        System.out.println("排序后的数组为:"+ Arrays.toString(arr));
        //测试一下快速排序的速度,给8w随机数组
        int[] arr = new int[80000];
        for (int i = 0; i < 80000; i++) {
            arr[i] =(int)(Math.random()*80000000);

        }
        //测试排序时间
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = format.format(date);
        System.out.println("排序前的时间:"+dateStr);

        int temp[] = new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("排序后的数组为:"+ Arrays.toString(arr));

        Date date1 = new Date();
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr1 = format1.format(date1);
        System.out.println("排序后的时间:"+dateStr1);

    }

结果:
在这里插入图片描述结果还是非常快的.这就是用空间换取时间的好处了.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值