排序算法-归并排序的时间复杂度分析

本文深入解析归并排序算法,阐述其递归与合并过程,展示如何通过分治思想实现高效排序,同时分析归并排序的时间复杂度、空间复杂度及稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序,其实就是递归+合并。

归并排序将数组取中间分为两部分,两个子数组分别各自再从中间分为两个子数组,一直分下去直到不能再分。分完之后,再按照子数组大小合并为为一个有序数组,然后层层向上合并,直到合并为一个有序的数组。

文字描述不理解的话,使用一副图来解释下:

其实归并排序的思想很简单,图中也描述的很清楚。

归并排序的时间复杂度为O(nlogn),跟冒泡、选择、插入这三种排序O(n^2)的时间复杂度不同,要有效率很多。

我们把代码呈上:

 /**
     * 归并排序
     * @param arr
     * @param n
     */
    public static void mergeSort(int[] arr,int n){
        mergeSort(arr,0,n-1);
    }

    /**
     * 递归程序
     * @param arr
     * @param p
     * @param r
     *
     */
    public static void mergeSort(int[] arr,int p,int r){
        if(p>=r){
            return;
        }
        int q = (p+r)/2;
        mergeSort(arr,p,q);
        mergeSort(arr,q+1,r);
        //合并
        merge(arr,p,q,r);
    }

    /**
     * 合并
     * @param arr
     * @param p
     * @param q
     * @param r
     */
    public static void merge(int[] arr,int p,int q,int r){
        int i =p,j=q+1,k=0;
        int[] temp = new int[r-p+1];
        while(i<=q && j<=r){
            //当两个区间中元素相等的时候,取arr(p,q)得加入temp,可以做到归并算法的稳定性
            if(arr[i] <= arr[j]){
                temp[k++]=arr[i++];
            }else{
                temp[k++]=arr[j++];
            }
        }
        //判断arr(p,q)和arr(q+1,r)哪个有剩余的数据
        int start=i,end=q;
        if(j<=r){
            start=j;
            end=r;
        }
        //将剩余数据拷贝到临时数组temp中
        while(start <= end){
            temp[k++]=arr[start++];
        }

        //将temp中的数据拷贝回arr(p,r)数组中
        for (int l = 0; l <= r-p; l++) {
            arr[p+l]=temp[l];
        }
    }

归并排序使用的是分治思想,分治思想简单说就是分而治之,将一个大问题分解为小问题,将小问题解答后合并为大问题的答案。乍一看跟递归思想很像,确实如此,分治思想一般就是使用递归来实现的。

需要说明的是,递归是代码实现,分治思想是解决问题的方法论,属于理论层面的

其实mergeSort这个函数就是使用递归层层分解问题的。可以看到将数组的大区间[p,r]从中间分开,分成两个小区间[p,q]和[q+1,r]

/**
     * 递归程序
     * @param arr
     * @param p
     * @param r
     *
     */
    public static void mergeSort(int[] arr,int p,int r){
        if(p>=r){
            return;
        }
        int q = (p+r)/2;
        mergeSort(arr,p,q);
        mergeSort(arr,q+1,r);
        //合并
        merge(arr,p,q,r);
    }

层层分解,直到满足递归终止条件:p>=r,就说明分到最后1个不能再分了。既然无法再分,那接着就进行合并了。看起来merge函数写的很复杂,其实如果理解了思想就非常容易理解了,千万不能被吓到。一切反动派都是纸老虎!

归并排序是原地排序算法吗?

不是原地算法,归并排序在合并函数中使用到了temp临时数组用来存放[p,r]区间元素,这个临时存储空间在merge函数结束后就释放了,所以归并排序的空间复杂度保持在O(n).

 

归并排序是稳定排序算法吗?

归并排序到底是不是稳定排序算法,关键在合并的时候,合并的时候可以选择对两个区间中相等的元素,取[p,q]的元素先放入temp数组中,保证了等值元素合并前后的存放顺序。所以归并排序是稳定排序算法。

 

归并排序算法的时间复杂度是多少?

假如n个元素使用归并排序的时间复杂度为T(n),那么由于归并排序使用的是分治思想,T(n)=2*T(n/2)+n,其中n就是两个子区间合并的时间复杂度,这个从合并函数可以看出来。可以推导出以下公式:

                        T(1) = C;   n=1 时,只需要常量级的执行时间,所以表示为 C。
                         T(n) = 2*T(n/2) + n; n>1

经过进一步推导,可以得到T(n)=2^k * T(n/2^k) + k * n,我们假设T(1)=T(n/2^k),也就是说当n/2^k个元素的进行归并排序,达到递归终止条件时,n/2^k=1,得到:k=logn

于是:

                                             T(n)=Cn+nlog2n

归并排序的时间复杂度就是O(nlogn),跟数组的有序度其实并没有什么关系,是非常稳定的时间复杂度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

公众号: 江南烟雨中

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值