摘要:归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

本文分享自华为云社区《一看就懂 ! 图解归并排序》,作者: bigsai 。

归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

一、算法思想

归并排序的主要思想是分治法。主要过程是:

1. 将n个元素从中间切开,分成两部分。

2. 将剩下的数组通过递归的方式一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了。

3. 从最底层开始逐步合并两个排好序的数列。把两个数组大小为1的合并成一个大小为2的有序数列,再把两个大小为2有序数列的合并成4的有序数列 … 直到全部小的数组合并起来。

二、思考

那么如何将两个有序数列合成一个有序的数列呢?

我们举个栗子把,一看就懂啦。

三、举个栗子

例如有数组 arr [3,7,8,10,2,4,6,9]; 我们可以把这个数组分成两个有序的子序列。

分别为 [3, 7, 8, 10] 和 [2, 4, 6, 9],并将其合并为有序序列[2,3,4,6,7,8,9,10]。

第一步:

把这两个小的数组拆分为 left 数组和 right 数组。如下图所示,使用 i 指向 left 的第一个元素, 使用 j 指向 right 的第一个元素。

第二步:

建立一个空数组 arr ,使用 k 指向数组第一个元素。

第三步:

比较 i 和 j 所指数字,将小的数字放在 k 所指位置。同时将小的数字所指位置和 k 所指位置向右移一位。

2 < 3 , 将 2 填入 arr 数组 ,同时右移 j 和 k。

3 < 4 , 将 3 填入 arr 数组 ,同时右移 i 和 k。

4 < 7,将 4 填入 arr 数组,同时右移 j 和 k。

6 < 7,将 6 填入 arr 数组,同时右移 j 和 k。

7 < 9,将 7 填入 arr 数组,同时右移 i 和 k。

8 < 9,将 8 填入 arr 数组,同时右移 i 和 k。

10 > 9,将 9 填入 arr 数组,同时右移 j 和 k。

可以发现此时 right 数组已经填完了,所以此时只需要把 left 数组剩下的数字填入 arr 即可。

一顿操作猛如虎,这样就把两个有序的数组通过归并的方式排好顺序啦,是不是很赞。

那么问题来了,难道归并排序只能排这种有序的数组么?

那出现一个无序的数组该咋办呢?例如这个数组现在变为 arr [8,7,2,10,3,9,4,6];

四、问题解决

此刻需要运用分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

其实上面第三部分就是治(conquer)的过程,将两个有序的序列合成为一个有序的序列。

小栗子:图解无序序列进行希尔排序。

五、算法实现

       #include <stdio.h>void merge(int arr[], int L, int M, int R) {int LEFT_SIZE = M - L;int RIGHT_SIZE = R - M + 1;int left[LEFT_SIZE];int right[RIGHT_SIZE];int i, j, k;// 填充左边的数组for (i=L; i<M; i++){left[i-L] = arr[i];}// 填充右边的数组for (i=M; i<=R; i++){right[i-M] = arr[i];}// for (int i=0; i<LEFT_SIZE; i++){// printf("%d\n",left[i]);// }// // for (int i=0; i<RIGHT_SIZE; i++){// printf("%d\n",right[i]);// }// 合并数组i = 0; j = 0; k = L;while (i < LEFT_SIZE && j < RIGHT_SIZE){if (left[i] < right[j]){arr[k] = left[i];i++;k++;}else{arr[k] = right[j];j++;k++;}}while(i < LEFT_SIZE){arr[k] = left[i];i++;k++;}while(j < RIGHT_SIZE){arr[k] = right[j];j++;k++;}}void mergeSort(int arr[], int L, int R){if (L == R){return;}else{int M = (L + R) / 2;mergeSort(arr,L,M);mergeSort(arr, M+1,R);merge(arr, L, M+1,R);}}int main(){// int arr[] = {3,7,8,10,2,4,6,9};int arr[] = {8,7,2,10,3,9,4,6};int L = 0;int M = 4;int R = 7;mergeSort(arr,L,R);for (int i=0; i<=R; i++){printf("%d\n",arr[i]);}}

输出:

六、算法分析

时间复杂度O(nlogn)。

空间复杂度O(N),归并排序需要一个与原数组相同长度的数组做辅助来排序。

稳定性:稳定,因为交换元素时,可以在相等的情况下做出不移动的限制,所以归并排序是可以稳定的。

七、适用场景

归并排序需要一个跟待排序数组同等空间的临时数组,因此,使用归并排序时需要考虑是否有空间上的限制。如果没有空间上的限制,归并排序是一个不错的选择。

点击关注,第一时间了解华为云新鲜技术~

归并排序,我举个例子你就看懂了相关推荐

  1. [vue] 你了解什么是高阶组件吗?可否举个例子说明下?

    [vue] 你了解什么是高阶组件吗?可否举个例子说明下? 高阶组件 高阶组件介绍 vue 高阶组件的认识,在React中组件是以复用代码实现的,而Vue中是以mixins 实现,并且官方文档中也缺少一 ...

  2. 深度学习究竟是什么,举个例子解释一下

    人工智能,就好像第四次工业革命,正从学术界的私藏,转变为一种能够改变世界的力量.尤其,以深度学习取得的进步为显著标志. 它让匍匐前进60年的人工智能一鸣惊人. 我们正降落到一片新大陆.深度学习带来的这 ...

  3. ES6——举个例子理解Promise的原理和使用

    1. Promise 之前 1.1 回调函数 回调函数:把函数A当作参数传递给另一个函数B调用,那么A就是回调函数. 一些例子 具名回调 function 你有几只狗(fn){fn('一只狗') } ...

  4. [vue] vue中什么是递归组件?举个例子说明下?

    [vue] vue中什么是递归组件?举个例子说明下? 组件自己调用自己,场景有用于生成树形结构菜单 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但坚持一定很酷.欢迎大家一起讨论 主 ...

  5. python语法简单吗_python基本语法练习实例 python好学吗? 语法简单吗? 举个例子?...

    Python学了基础语法,如何练习一些项目呢?学了基础语法,你学一学Django框架和爬虫吧,我现在正在学爬虫相关的教程,黑马程序员视频库里就有相关的教程,我就是在那里下载的,目前正在学. 推荐几个适 ...

  6. 电压和电流反馈判别及例子,绝对让你通透,其实也没有那么难,一次就看懂!从此终于搞懂了电压反馈和电流反馈!

    电压和电流反馈判别及例子,其实也没有那么难,绝对让你通透,一次就看懂!从此终于搞懂了电压反馈和电流反馈! 一个简单粗暴的判断方法: 先看反馈是否直接连到Uo输出端(若不是直接从输出端引出,则为电流反馈 ...

  7. 2021-07-18:最高的广告牌。你正在安装一个广告牌,并希望它高度最大。这块广告牌将有两个钢制支架,两边各一个。每个钢支架的高度必须相等。你有一堆可以焊接在一起的钢筋 rods。举个例子,如果钢筋

    2021-07-18:最高的广告牌.你正在安装一个广告牌,并希望它高度最大.这块广告牌将有两个钢制支架,两边各一个.每个钢支架的高度必须相等.你有一堆可以焊接在一起的钢筋 rods.举个例子,如果钢筋 ...

  8. 通过例子10分钟快速看懂pad_sequence、pack_padded_sequence以及pad_packed_sequence

    前言 import torch import torch.nn as nnfrom torch.nn.utils.rnn import pad_sequence from torch.nn.utils ...

  9. 归并排序时间复杂度_一文带你读懂排序算法(四):归并算法

    点击上方蓝字关注我们 归并排序的基本思想核心是分治,就是把一个复杂的问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,直到子问题可以简单的直接求解,最原问题的解就是子问题解的合并.算 ...

最新文章

  1. ABAP几种内表的操作
  2. zookeeper 命令
  3. 汉军Hundre考勤数据库数据表分析总结
  4. CCF201409-2 画图
  5. 华信mysql数据恢复_华信Mysql数据库修复工具1.0
  6. Java 程序设计基础(第四版)上
  7. zutuanxue.com-DNS服务器
  8. iOS RSA加签 验签 与Java同步 pkcs8 pkcs1
  9. ubuntu20.04安装有道词典
  10. 墨刀如何导出html,墨刀元素如何快速拷贝到Axure里?
  11. 需要密码才能打开的word文件
  12. 转载:云计算必将极大影响未来--云泉
  13. java 隐藏父类方法,java 子类继承父类成员变量的隐藏、实现方法的重写
  14. mysql条件增量同步命令_DataX3 Mysql增量同步ES
  15. C# 实现视频监控系统(附源码)
  16. Rust:用问号 ?操作符简化错误信息的判断
  17. 开发android 输入法,Android输入法开发实例解析 Android开发技术
  18. python里不能调用random库_Python标准库教程—random模块
  19. android service什么时候销毁,阳光沙滩-android 通过AppWidgetProvider 启动的Service会自动销毁问题...
  20. 144显示器只有60_DIY老司机:吃鸡显示器非得用144Hz,60Hz就不行?

热门文章

  1. 被坑了 | 那个写公众号,开网店的小小,被花式坑了!
  2. 实践 | 在MySql中,这四种方法可以避免重复插入数据!
  3. gitlab nginx php解析,GitLab-webhook-PHP 详解 GitLab Webhooks 自动部署应用服务器
  4. linux usb无法识别,求助:USB无法识别
  5. win 二进制门安装mysql_MySQL5.7 windows二进制安装
  6. Java实现的一个简单的模板渲染
  7. A Spy in the Metro UVA - 1025
  8. VC++2012编程演练数据结构《35》多路平衡归并
  9. 学生用计算机shift,电脑Shift键你会用吗
  10. RTT内核对象——对象理解