排序算法——归并排序

好长时间没有更新了,有没有想我呢?我们接着说排序算法吧

今天为大家梳理的是归并排序

合并排序(Merge Sort)算法就是将多个有序数据表合并成一个有序数据表。如果参与合并的只有两个有序表,则称为二路合并。对于一个原始的待排序序列,往往可以通过分割的方法来归结为多路合并排序。下面以二路合并为例,来介绍合并排序算法。

合并排序算法
一个待排序的原始数据序列进行合并排序的基本思路是,首先将含有n个结点的待排序数称列看作由n个长度为1的有序子表组成,将其依次两两合并,得到长度为2的若干有序子表:然后,再对这些子表进行两两合并,得到长度为4的若干有序子表.…,重复上述过程,一直到最后的子表长度为n,从而完成排序过程。

1.合并排序算法原理
下面通过一个实际的例子来分析合并排序算法的执行过程,以加深读者的理解。

假设有9个需要排序的数据序列 67、65、77、38、97、3、33、49、34。合并排序算法的操作步骤如下:
(1)首先将9个原始数据看成9个长度为1的有序子表。每一个子表中只有一个数据,这里可以认为单个数据是有序的。
(2)将这9个有序子表两两合并,为了方便,将相邻的子表进行两两合并。例如,将第1、2个合并在一起,第3、4个合在一起···,最后一个没有合并的,就单独放在那里,直接进入下一遍合并,如图所示。

原始数据:
在这里插入图片描述

(3)经过第1遍的合并,得到长度为2的有序表序到,再将这些长度为2的有序却学。
两合并,如图所示。
第1遍合并结果:

在这里插入图片描述

(4)重复两两合并,经过第2遍合并,得到长度为4的有序表序列,再将这些长度为4的有序表进行两两合并,如图所示。
第2遍合并结果:
在这里插入图片描述

(5)经过第3遍合并,得到长度为8的有序表序列,以及最后只有一个元素的序列,如图所示:
第3遍合并结果:
在这里插入图片描述
(6)将这两个序列进行合并,即可完成合并排序,最后的结果如图所示:
第四遍合并结果:

在这里插入图片描述
2.合并排序算法

代码如下:

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

        //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数组的元素copy到arr
        //注意并不是每次都拷贝所有
        t=0;
        int tempLeft=left;//
        //第一次合并时tempLeft=0,right=1  //tempLeft=2,right=3
        // tempLeft=0,right=3  //tempLeft=0,right=7
        //System.out.println("tempLeft="+tempLeft+"\t"+"right="+right);
        while(tempLeft<=right){
            arr[tempLeft]=temp[t];
            t+=1;
            tempLeft+=1;
        }

    }

运行结果如图所示:
排序算法——归并排序_第1张图片

我们还可以去测试它的运行效率,这里给出代码,大家自行检测:

package DataStructures.pro0925Sort;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @Author DreamYee
 * @Create 2019/11/16 17:15
 */
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];
        System.out.println("归并排序前:"+ Arrays.toString(arr));
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("归并排序后:"+ Arrays.toString(arr));

        /*
        //创建要给80000个数据的数组
        int[] arr=new int[800000];
        int[] temp=new int[arr.length];//归并排序需要额外的空间
        for(int i=0;i<800000;i++){
            arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)数
        }

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

        mergeSort(arr,0,arr.length-1,temp);

        Date date2=new Date();
        String date2Str=simpleDateFormat.format(date2);
        System.out.println("排序后的时间:"+date2Str);

        //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,right,mid,temp);

        }
    }

    //合并的方法

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

        //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数组的元素copy到arr
        //注意并不是每次都拷贝所有
        t=0;
        int tempLeft=left;//
        //第一次合并时tempLeft=0,right=1  //tempLeft=2,right=3
        // tempLeft=0,right=3  //tempLeft=0,right=7
        //System.out.println("tempLeft="+tempLeft+"\t"+"right="+right);
        while(tempLeft<=right){
            arr[tempLeft]=temp[t];
            t+=1;
            tempLeft+=1;
        }

    }
}

好啦,归并排序就说到这,大家有什么可以留言哦

你可能感兴趣的:(java常用排序算法,数据结构,算法排序)