经典算法(5)-归并排序

归并排序是一种基于分治法的高效排序算法,将数组拆分成相等或接近相等的子组,直至每个子组只剩一个元素,然后逐步合并并排序这些子组,最后形成一个完全有序的数组。文章通过图解和代码展示了归并排序的过程,并指出其时间复杂度为O(nlogn)。

经典算法(5)- 归并排序

概述

归并排序是采用分治法的一个非常典型的应用,是建立在归并操作上的一种有效排序算法,它是通过尽可能的将一组数据拆分成两个元素个数相等的子组(只是尽可能的个数相等),并且对每一个子组继续拆分,直到拆到每个子组的个数都是1为止,然后再将相邻的两个子组合称一个大的有序子组,然后不断重复合并的步骤,直到最终只有一个组为止,其实字面上看该排序算法不难想象,无非就是把数组拆个一个一个的元素,然后相邻再排序然后再合成,直到成一个数组,但是代码实现起来还是有一些细节的。

图解

在这里插入图片描述
如上图是分的过程,原数据是[5,6,2,4,8,3,7,1]第一次把原数据分成两组[5,6,2,4]和[8,3,7,1]。第二次把两组数据分成四组[5,6],[2,4],[8,3],[7,1]。最后一次把每个数据都分成独立的一组5,6,2,4,8,3,7,1。
在这里插入图片描述
如上图是治的过程,不难发现,排序的过程都是在治的时候进行的,第一次,把独立一组的每个元素,每相邻两个进行排序并合并,变成四组元素5,6变成[5,6],2,4变成[2,4],8,3变成[8,3],7,1变成[7,1]。第二次,每相邻两组排序并且合并成一组,总共两组,[5,6],[2,4]变成[2,4,5,6],[8,3],[7,1]变成[1,3,7,8]。第三次,每相邻两组排序并且合并成一组,总共一组,[2,4,5,6],[1,3,7,8]变成[1,2,3,4,5,6,7,8]。

代码

public class Merge {
    //辅助数组
    private int[] assist;
    //对数组array进行排序
    public void sort(int[] array){
        //初始化辅助数组assist,数组长度和待排序数组长度一样即可
        assist = new int[array.length];
        //定义一个lo变量和hi变量,分别记录数组中最小和最大的索引
        int lo = 0;//第一个数的索引为0,所以定义lo的初始值为0
        int hi = array.length - 1;//最后一个数的索引为array.length - 1,所以定义hi的初始值为array.length - 1
        //调用sort重载方法完成数组array中,从索引lo到索引hi的元素排序
        sort(array,lo,hi);
    }
    //对数组array中从lo到hi进行排序
    private  void sort(int[] array,int lo,int hi){
        //需要做安全性校验,排序的
        if(hi<=lo){
            return;
        }
        //对lo到hi进行分组
        int mid = lo+(hi-lo)/2;//例如lo是5,hi是9.那么mid是7
        //分别对每一组进行分组和排序
        sort(array,lo,mid);
        sort(array,mid+1,hi);
        //在把两个组进行归并
        merge(array,lo,mid,hi);
    }
    //对数组中,从lo到mid为一组,从mid+1到hi一组,对这两组进行归并
    private void merge(int[] array,int lo,int mid,int hi){
        //定义三个指针,作用是指向左右数据当前比较的数据以及辅助数据当前的索引位置
        int i = lo;
        int p1 = lo;
        int p2 = mid+1;
        //遍历,移动p1指针和p2指针,比较对应索引处的值,找出小的放到辅助的指针索引处
        while(p1<=mid && p2<=hi){
            //比较指针索引处的值
            if(array[p1]<array[p2]){
                assist[i] = array[p1];
                //放完后p1和i要往后挪一位
                i++;
                p1++;
            }else{
                assist[i] = array[p2];
                i++;
                p2++;
            }
        }
        //遍历,如果p1的指针没有走完,那么顺序p1的指针  ,把对应的数据写进辅助数组
        while(p1<=mid){
            assist[i] = array[p1];
            i++;
            p1++;
        }
        //遍历,如果p2的指针没有走完,那么顺序p2的指针  ,把对应的数据写进辅助数组
        while(p2<=hi){
            assist[i] = array[p2];
            i++;
            p2++;
        }
        //把辅助数组的元素拷贝到原数组里
        for (int j = lo; j <= hi; j++) {
            array[j] = assist[j];
        }
    }
}

时间复杂度

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值