合并排序,大致思想便是先将数组中的元素拆分成若干小部分,然后再将这些小部分按照顺序进行重新组合,从而实现排序。很明显,这里用到了分治法的思想,即将一个大问题分成若干个相同的小问题,因为问题规模变小了,所以解决问题的难度也随之减小,试想一下,对一个拥有10000个元素的数组进行排序简单还是对一个只拥有1个元素的数组进行排序简单?答案很明显。

对于合并排序,将大问题分成若干小问题是一件很容易的事情,只需要不断递归即可,其中最主要的难点就是将这些小问题解决之后,如何再将这些小问题合并起来,若是处理不好,很可能就导致算法失败。那么接下来就开始正式的讲解。

先上伪代码

因为伪代码没有其他语言的语法限制,能够有助于我们更好地将注意力放在算法上,所以这里我们先用伪代码来讲述一下主要思想:

algorithm mergeSort(A[0..n-1])
//递归调用mergeSort来对数组A[0..n-1]排序
//输入:一个可排序的数组A[0..n-1]
//输出:非降序排列的数组A[0..n-1]
if n > 1  //将数组中的n个元素分成n组copy A[0..(n/2)] to B[0..(n/2)]copy A[(n/2)..n-1] to C[0..(n/2)-1]mergeSort(B[0..(n/2)])mergeSort(C[0..(n/2)-1])merge(B, C, A)  //将B和C合并到A中algorithm merge(B[0..n-1], C[0..m-1], A[0..n+m-1])
//将两个有序数组B和C合并到A中
//输入:两个有序数组和一个待整合数据的数组
//输出:A[0..n+m-1]中已经有序存好了B和C中的数据
i <- 0;j <- 0;k <- 0
while i < n and j < m doif B[i] <= C[j]A[k] <- B[i]i <- i + 1else A[k] <- C[j]j <- j + 1k <- k + 1
if i = n  //说明B中的所有元素已经存放到A中,即C中的部分元素为存入到A中copy C[j..m-1] to A[k..n+m-1]
else copy B[i..n-1] to A[k..n+m-1]

因为不管怎样,一个元素的数组绝对是最好排序的,因为不需要排序,所以我们一开始就需要将整个数组分成n个组,之后再慢慢地合并,如下图便是合并排序的一个例子:

代码实现

这里我是用的C++来实现该算法:

关键部分:

void merge(int* B, int lenB, int* C, int lenC, int* A, int lenA) {int i = 0, j = 0, k = 0;while (i < lenB && j < lenC) {if (B[i] <= C[j]) A[k++] = B[i++];else A[k++] = C[j++];}if (i == lenB) {while (j < lenC) A[k++] = C[j++];} else {while (i < lenB)A[k++] = B[i++];}
}void mergeSort(int* A, int lenA) {if (lenA > 1) {int n1 = lenA / 2;int n2 = lenA - n1;int* B = (int*)malloc(sizeof(int) * n1);int* C = (int*)malloc(sizeof(int) * n2);for (int i = 0; i < n1; i++) {B[i] = A[i];}for (int i = 0; i < n2; i++) {C[i] = A[n1 + i];}mergeSort(B, n1);mergeSort(C, n2);merge(B, n1, C, n2, A, lenA);free(B);free(C);}
}

然后在main()函数中调用:

int main() {cout << "排序前的数组:" << endl;for (int i = 0; i < 10; i++) {cout << A[i] << " ";}cout << endl;mergeSort(A, 10);cout << "排序后的数组:" << endl;for (int i = 0; i < 10; i++) {cout << A[i] << " ";}cout << endl;return 0;
}

运行结果如下:

复杂度分析

合并排序的复杂度要分成两部分来看,一部分是分治,另一部分则是合并,

其中合并部分,最差执行n-1次比较,最优执行n/2次比较,都是O(n),

因此得到如下公式:
T(n)={0,n=12T(n/2)+O(n),n>1T(n)=\begin{cases} 0 \quad\quad\quad\quad\quad\quad,n=1\\ 2T(n/2)+O(n), n>1\end{cases} T(n)={0,n=12T(n/2)+O(n),n>1​
再由主定理可得合并排序的时间复杂度为O(nlogn),并且无论是最优最差还是平均,复杂度都是O(nlogn)。

接下来我们再来看看合并排序的空间复杂度,

我们同样可以得到如下公式:
S(n)={0,n=12S(n/2)+O(n),n>1S(n)=\begin{cases} 0 \quad\quad\quad\quad\quad\quad,n=1\\ 2S(n/2)+O(n), n>1\end{cases} S(n)={0,n=12S(n/2)+O(n),n>1​
所以我们也可以马上知道合并排序的空间复杂度也为O(nlogn)。

由此我们也可以发现,虽然合并排序的时间复杂度比较好,但是空间复杂度确实太高了,相比冒泡排序、选择排序这些在位排序而言,占用的额外空间实在是太多了。

因此针对合并排序的改进方向便是减小空间复杂度。

参考资料

《算法设计与分析基础》第三版以及老师的课件

合并排序(归并排序)相关推荐

  1. c++归并排序_合并排序法

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

  2. C语言归并排序(合并排序)

    归并排序也称合并排序,其算法思想是将待排序序列分为两部分,依次对分得的两个部分再次使用归并排序,之后再对其进行合并.仅从算法思想上了解归并排序会觉得很抽象,接下来就以对序列A[0], A[l]-, A ...

  3. 归并排序(递归实现+非递归实现+自然合并排序)

    归并排序的确是分治思想的经典代表.写了很多次,这次又有新的收获,过去用的是递归的实现方式,理论上任何用递归方法实现的代码都可以转换为非递归的形式,所以此例也不例外.然后再用非递归的实现方法上进行改进, ...

  4. 【学习记录】合并排序(归并排序)-分治法-计算机算法

    讲解过程-合并算法讲解 产生随机数表的代码 #include<iostream> #include<fstream> #include<stdlib.h> #inc ...

  5. 从合并排序算法看“分治法”

    本文内容 分治策略 分治步骤 从合并排序看"分治策略" 分治策略 分治法(divide-and-conquer),"分治法策略"是一种很重要的算法.顾名思义,& ...

  6. 看图轻松理解数据结构与算法系列(合并排序)

    前言 推出一个新系列,<看图轻松理解数据结构和算法>,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握.本系列包括各种堆.各种队列.各种列表.各种树.各种图.各种排序等等几十篇的 ...

  7. 程序员面试系列——合并排序(递归实现)

    合并排序基本思想 合并排序,或者叫归并排序,在算法思想中属于分治法.对于一个需要排序的数组,合并排序把它一分为二,并对每个子数组递归排序,然后把这两个排好序的子数组合并为一个有序数组. 本文要介绍两种 ...

  8. C语言合并排序实例代码

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105089953 并 ...

  9. 合并排序(Java)-解析

    合并排序-解析 算法设计有很多方法,前面说过的插入排序使用的是增量(incremental)方法:在排好子数组 A[ 1--j -1] 后,将元素 A[j] 插入,形成排好序的子数组 A[ 1--j] ...

最新文章

  1. .net应用程序如何批上XP的外衣?
  2. 自顶而下系统构架分析
  3. C语言经典例25-阶乘累加求和
  4. [学习笔记]模拟电路技术
  5. 微服务架构日志集中化 安装 EFK (Fluentd ElasticSearch Kibana) 采集nginx日志
  6. java接口课程_用java定义一个接口,用于查询课程
  7. 逻辑人渴望控制那些让他们感兴趣的东西
  8. English trip -- MC(情景课)3 C Do you have a sister?
  9. linux怎么退出telnet端口,CentOS下怎么退出telnet
  10. linux postgresql 恢复数据库,PostgreSQL数据库备份和恢复
  11. matlab iir滤波器设计 实验报告,IIR数字滤波器的设计实验报告
  12. hadoop安装常见问题
  13. 使用61850网关实现modbus和电力iec61850协议的转换
  14. IE浏览器自带打印控件WebBrowser
  15. python语言程序设计基础笔记(三)计算机思维
  16. ChinaSoft 论坛巡礼 | CCF-华为胡杨林基金-软件工程专项论坛
  17. Python 自动获取 Bing 壁纸
  18. @Scripts “does not exist”
  19. linux宝塔面板打不开 ssh也连不上,SSH能访问,但是宝塔面板打不开,输入bt命令无任何反应!...
  20. 在Excel中如何制作K线

热门文章

  1. 【并行算法】问题的基本求解过程和并行计算机模型
  2. web2.0相关介绍
  3. 数据包络分析-二阶段网络带feedback(第二篇)
  4. ChatGPT:你真的了解网络安全吗?浅谈攻击防御进行时之传统的网络安全
  5. How to do presentation
  6. GVINS编译出现大量的error: ‘CV_CALIB_CB_ADAPTIVE_THRESH’ was not declared in this scope错误
  7. 观瞻A8音乐原创中国颁奖典礼-_-
  8. Nexus私有仓库错误代码500
  9. solr中文键变成下划线
  10. 登陆界面设计(设置按回车登录)