排序算法之归并排序(Java实现)

目录

归并排序的介绍

归并排序实现思想

 归并排序代码讲解

理解难点:


归并排序的介绍

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

归并排序的时间,空间复杂度:

归并排序是一个效率比较快的算法,所以我们有必要了解一下该算法的实现思想(如果能自己写出代码是更好的)。

归并排序实现思想

归并排序的过程由两个过程构成。

分: 简单来说,就是把一个待排序的数组,分成一个又一个的子数组,将他们排成有序的数组;

治:   将这些排序完成的子数组,合并在一起,完成排序。

上一张图大家可能会有更好的理解:

归并排序基本思想

 归并排序代码讲解

为了更好更容易的理解该算法,我先摆上代码,通过理解代码更清晰的掌握该算法思想。

public class MergeSort {
    public static void main(String[] args) {
        int[] arr = new int[]{8,4,5,7,1,3,6,2};


        int[] temp = new int[arr.length];

        mergeSort(arr,0,arr.length - 1,temp); // left:0  right:7

        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 右边有序序列的初始索引
     */
    public static void merge(int[] arr , int left , int mid ,int right , int temp[]){
        int i = left; // 初始化i , 表示左边有序序列的初始索引
        int j = mid + 1; //初始化j ,右边有序序列的初始索引
        int t = 0; //指向temp数组(辅助数组)的当前索引

        //(1)
        //先把左右俩边的数据按照规则填充到temp数组
        //直到两边的有序序列,有一边处理完毕为止

        while(i <= mid && j <= right){
            //如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
            //就将左边的当前元素,拷贝到temp数组
            if(arr[i] <= arr[j]){
                temp[t] = arr[i];
                t++;
                i++;
            }else{
                //反之就将右边的当前元素,拷贝到temp数组
                temp[t] = arr[j];
                t++;
                j++;
            }
        }


        //(2)
        //把有剩余数据的一边的数据全部填充到temp中
        while (i <= mid){//左边的有序序列还有剩余元素
            temp[t] = arr[i];
            t++;
            i++;
        }

        while (j <= right){//右边的有序序列还有剩余元素
            temp[t] = arr[j];
            t++;
            j++;
        }


        //(3)
        //将temp数组的元素拷贝到arr
        //这里的代码其实就是一个数组的拷贝过程
        t = 0;
        int tempLeft = left; //templeft是辅助指针,left就是temp[]的首索引
        System.out.println("tempLeft=" + tempLeft + "  right=" + right);
        while(tempLeft <= right){
            arr[tempLeft] = temp[t];
            t++;
            tempLeft++;
        }

    }
}

 我们先来看的这个过程:

  • 在这个过程中,我们需要一个temp[]辅助数组来帮助我们完成这个过程。
  • 该方法需要的参数有,待排序的数组,数组的初始索引,数组的末位置索引,数组的中间索引,已经temp[]辅助数组


 

 待排序的数组是: 8  5  4  7  1  3  6  2;

分之后的两部分别为:4 5 7 8  ;  1 2 3 6

  1. 分别定义两个指针(图中的i和j),指向两个子数组的首索引(4和1);
  2. 通过比较两个的大小,小的一方,放入到temp数组中,然后指针向后移动;直到一个子数组遍历结束为止;
  3. 然后将未遍历完的子数组的数据也放入到temp数组中去;
  4. 最后将temp[]辅助数组的内容全部拷贝到原数组中去;

理解难点:

我个人认为在这个算法的代码中,治的代码倒是很好理解,主要是分+治的这个过程用到了递归,如果对递归掌握的不太清楚的话,可能还真有点迷糊,所以我就尽我可能的分享给大家我所理解的。

 

整个递归的过程还是蛮复杂的,这一篇可能是写给自己的理解的,如果你看不懂也没关系,确实逻辑有点乱,过段时间我可能重新写一次,那时候可能会更加让读者易懂~~

 执行结果:

 文中的一些图片是借用别人的。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值