归并排序

归并排序就是讲两个有序的数组合成一个有序的数组
归并排序主要做两件事:
1.分解:将序列每次折半拆分
2.合并:将划分后的序列段两两排序合并
转载自https://blog.csdn.net/k_koris/article/details/80508543

注:内容,图片来自于慕课网liuyubobobo老师的课程。

算法复杂度:O(nlogn)

也许有很多同学说,原来也学过很多O(n^2)或者O(n^3)的排序算法,有的可能优化一下能到O(n)的时间复杂度,但是在计算机中都是很快的执行完了,没有看出来算法优化的步骤,那么我想说有可能是你当时使用的测试用例太小了,我们可以简单的做一下比较:

 

当数据量很大的时候 nlogn的优势将会比n^2越来越大,当n=10^5的时候,nlogn的算法要比n^2的算法快6000倍,那么6000倍是什么概念呢,就是如果我们要处理一个数据集,用nlogn的算法要处理一天的话,用n^2的算法将要处理6020天。这就基本相当于是15年。一个优化改进的算法可能比一个比一个笨的算法速度快了许多,这就是为什么我们要学习算法。

核心思想:分治。

下面我们来看归并排序的思路(先讲思路再来具体讲归并的细节)

 

归并排序(Merge Sort)

 

 

 

 

当我们要排序这样一个数组的时候,归并排序法首先将这个数组分成一半。如图:

 

 

 

然后想办法把左边的数组给排序,右边的数组给排序,之后呢再将它们归并起来。当然了当我们对左边的数组和右边的素组进行排序的时候,再分别将左边的数组和右边的数组分成一半,然后对每一个部分先排序,再归并。如图:

 

 

 

对于上面的每一个部分呢,我们依然是先将他们分半,再归并,如图:

 

 

 

分到一定细度的时候,每一个部分就只有一个元素了,那么我们此时不用排序,对他们进行一次简单的归并就好了。如图:

 

 

 

归并到上一个层级之后继续归并,归并到更高的层级,如图:

 

 

 

直至最后归并完成。

 

 

 

那么如何归并呢?我们是否可以用O(n)的算法将两个数组归并到一起形成一个数组呢?如果可以的话,我们将可以用递归的过程来实现整个归并。这是你想起来很简单但是操作起来并不是那么简单的问题。

 

 

归并细节:

比如有两个已经排序好的数组,如何将他归并成一个数组?

我们可以开辟一个临时数组来辅助我们的归并。也就是说他比我们插入排序也好,选择排序也好多使用了存储的空间,也就是说他需要o(n)的额外空间来完成这个排序。只不过现在计算机中时间的效率要比空间的效率重要的多。无论是内存也好还是硬盘也好可以存储的数据越来越多,所以设计一个算法,时间复杂度是要优先考虑的。

 

 

 

整体来讲我们要使用三个索引来在数组内进行追踪。

 

 

 

 

 

 

蓝色的箭头表示最终选择的位置,而红色的箭头表示两个数组当前要比较的元素,比如当前是2与1比较,1比2小,所以1放到蓝色的箭头中,蓝色的箭头后移,1的箭头后移。

 

 

 

 

 

然后2与4比较,2比4小那么2到蓝色的箭头中,蓝色箭头后移,2后移,继续比较.......

 

 

归并思路就是这样了,最后唯一需要注意的是那个先比较完的话,那么剩下的直接不需要比较,把后面的直接移上去就可以了,这个需要提前判定一下。

 

归并排序代码如下:

 

 

 

template<typename T>
void __merge(T arr[],int left,int mid,int right){
    T aux[right-left+1];
    for(int i=left;i<=right;i++)
        aux[i-left]=arr[i];
    int i=left,j=mid+1;
    for(int k=left;k<=right;k++) {
        if (i > mid) {
            arr[k] = aux[j - left];
            j++;
        } else if (j > right) {
            arr[k] = aux[i - left];
            i++;
        } else if (aux[i - left] < aux[j - left]) {
            arr[k] = aux[i - left];
            i++;
        } else {
            arr[k] = aux[j - left];
            j++;
        }
    }

}

template <typename T>
void __mergeSort(T arr[],int left,int right){
    if(left>=right)
        return;
    int mid=left+(right-left)/2;
    __mergeSort(arr,left,mid);
    __mergeSort(arr,mid+1,right);
    __merge(arr,left,mid,right);
}

template <typename T>
void mergeSort(T arr[],int n){
    __mergeSort(arr,0,n-1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值