归并排序解释

归并排序 Merge Sort 是典型的分治法的应用,其算法步骤完全遵循分治模式。

分治法思想

分治法 思想: 将原问题分解为几个规模较小但又保持原问题性质子问题递归求解这些子问题,然后再合并这些子问题的解,最终得到原问题的解。

分治模式每层递归步骤

1、分解原问题为若干个子问题;

2、解决子问题。递归求解子问题,当子问题规模足够小时,可以直接求解;

3、合并这些子问题的解构成原问题的解。

归并排序的分治模式

1、分解未排序 n 个元素的序列成 各有 n/2 个元素的连续子序列;

2、递归排序两个连续子序列;

3、合并两个已排序的连续子序列构成整个完成排序的序列。


归并排序递归树

我们以序列 [7, 4, 8, 1, 3, 5, 6, 2] 为例构建一个归并排序的递归树

上半部分递归树为将当前长度为 n 的序列拆分成长度为 n/2 的子序列,下半部分递归树为合并已经排序的子序列。


时间复杂度

假设时间复杂度为 T(n),在递归解决当前两个规模为 n/2 的子问题时,我们需要消耗 2T(n/2)* 的时间。

在合并过程中,对于一个具有 n 个元素的序列,我们需要消耗O(n)的时间。

故时间复杂度如下


归并排序核心代码

void Merge(int a[], int left, int mid, int right){
int temp[right - left + 1]; //临时数组用于存储排序时的数
int i = left; //分成两块 i指向左边的数字 j指向右边的数字
int j = mid + 1;
int k = 0; //k用于存储数字到临时数组 while( i <= mid && j <= right ){
if(a[i] < a[j]) //永远都是 i 和 j 指向的数进行比较
temp[k++] = a[i++]; //谁小,谁就先放到临时数组中
else
temp[k++] = a[j++];
} while( i <= mid ) //如果左边还有数没放上去,就依次放上去
temp[k++] = a[i++];
while( j <= right ) //如果是右边还有同上
temp[k++] = a[j++]; for(int m = left, n = 0; m <= right; m++, n++)//读取临时数组中的数
a[m] = temp[n];
} void Merge_Sort(int a[], int left, int right){
if( left == right )
return; int mid = (left + right)/2;
//递归拆分成较小规模子序列排序
Merge_Sort(a, left, mid);
Merge_Sort(a, mid + 1, right);
Merge(a, left, mid, right); //合并较小规模问题解
}

完整程序源代码

#include<iostream>
#include<ctime>
using namespace std; void Merge(int a[], int left, int mid, int right){
int temp[right - left + 1]; //临时数组用于存储排序时的数
int i = left; //分成两块 i指向左边的数字 j指向右边的数字
int j = mid + 1;
int k = 0; //k用于存储数字到临时数组 while( i <= mid && j <= right ){
if(a[i] < a[j]) //永远都是 i 和 j 指向的数进行比较
temp[k++] = a[i++]; //谁小,谁就先放到临时数组中
else
temp[k++] = a[j++];
} while( i <= mid ) //如果左边还有数没放上去,就依次放上去
temp[k++] = a[i++];
while( j <= right ) //如果是右边还有同上
temp[k++] = a[j++]; for(int m = left, n = 0; m <= right; m++, n++)//读取临时数组中的数
a[m] = temp[n];
} void Merge_Sort(int a[], int left, int right){
if( left == right )
return; int mid = (left + right)/2;
//递归拆分成较小规模子序列排序
Merge_Sort(a, left, mid);
Merge_Sort(a, mid + 1, right);
Merge(a, left, mid, right); //合并较小规模问题解
} void Show(int a[], int n){
for(int i = 0; i < n; i++)
cout<<a[i]<<" ";
cout<<endl;
} main(){
int a[50];
srand((int)time(0));
for(int i = 0; i < 50; i++)
a[i] = rand() % 100 + 1;
Show(a, 50); Merge_Sort(a, 0, 50); cout<<endl<<endl;
Show(a, 50);
}

程序运行结果图

[排序算法] 归并排序 (C++)的更多相关文章

  1. 经典排序算法 - 归并排序Merge sort

    经典排序算法 - 归并排序Merge sort 原理,把原始数组分成若干子数组,对每个子数组进行排序, 继续把子数组与子数组合并,合并后仍然有序,直到所有合并完,形成有序的数组 举例 无序数组[6 2 ...

  2. 数据结构和算法(Golang实现)(23)排序算法-归并排序

    归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...

  3. 使用 js 实现十大排序算法: 归并排序

    使用 js 实现十大排序算法: 归并排序 归并排序 refs js 十大排序算法 All In One https://www.cnblogs.com/xgqfrms/p/13947122.html ...

  4. java泛型中使用的排序算法——归并排序及分析

    一.引言 我们知道,java中泛型排序使用归并排序或TimSort.归并排序以O(NlogN)最坏时间运行,下面我们分析归并排序过程及分析证明时间复杂度:也会简述为什么java选择归并排序作为泛型的排 ...

  5. js 实现排序算法 -- 归并排序(Merge Sort)

    原文: 十大经典排序算法(动图演示) 归并排序 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得 ...

  6. javascript排序算法-归并排序

    归并排序 概念:归并排序是一种分治算法.其思想是将原始数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组归并成较大的数组,直到最后只有一个排序完毕的大数组. 时间复杂度: O(nlogn) ...

  7. 八大排序算法——归并排序(动图演示 思路分析 实例代码java 复杂度分析)

    一.动图演示 二.思路分析 归并排序就是递归得将原始数组递归对半分隔,直到不能再分(只剩下一个元素)后,开始从最小的数组向上归并排序 1.  向上归并排序的时候,需要一个暂存数组用来排序, 2.  将 ...

  8. 排序算法-归并排序(Java)

    package com.rao.sort; import java.util.Arrays; /** * @author Srao * @className MergeSort * @date 201 ...

  9. 疯子的算法总结(六) 复杂排序算法 ① 归并排序 merge_sort()

    归并排序采取了分治的思想,每次分别排左半边和右半边,不断递归调用自己,直到只有一个元素递归结束,开始回溯,调用merge函数,合并两个有序序列,再合并的时候每次给末尾追上一个最大int这样就不怕最后一 ...

  10. JavaScript排序算法——归并排序

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

随机推荐

  1. Elasticsearch7.6.2 RestHighLevelClient查询用法 must should(and or 关系)

    1. 引入jar <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId&g ...

  2. idea每次换行后光标都跑到最左边问题

    最进用idea时发现每次换行之后一段时间光标会自动跑到最左边,默认把我的首行空格删掉了 IDEA版本为:IntelliJ IDEA 2020.2.3 x64

  3. kubeadm init 命令执行流程

  4. MongoDB 单实例节点主机的用户和权限一般操作步骤

    步骤总结: 1.先正常启动 2.创建用户,创建数据库病授权用户 3.关闭程序,开启安全,然后启动 4.使用账号和密码连接 按未开启认证的方式(配置文件中没开启安全选项并且启动命令中不添加 --auth ...

  5. .NET 反向代理 YARP 跨域请求 CORS

    使用过 nginx 的小伙伴应该都知道,这个中间件是可以设置跨域的,作为今天的主角,同样的 反向代理中间件的 YARP 毫无意外也支持了跨域请求设置. 有些小伙伴可能会问了,怎样才算是跨域呢? 在 H ...

  6. Linux 宝塔部署 ASP.NET Core 应用

    第一步,发步应用 我这是一个API 应用和 MVC 应用 设置,服务器上要运行的端口 API 端口5000 MVC 端口5001 打包文件夹,发步 1.桌面新建俩个文件夹 2.右键项目发步,选中iis ...

  7. SQLServer配置开启TCP/IP连接

    一 先启用SQLServer的TCP/IP协议 1.1 打开SQLServer配置管理器 1.2 启用TCP/IP 二 设置SQLServer端口 2.1 双击TCP/IP,弹出属性设置框 2.2 将 ...

  8. 关于history.back()、history.go()回退但无法刷新页面的问题

    window.history.back(); 这样确实可以做到后退的功能,但是项目中,常常并不只是后退就能完成需求,往往需要在后退的同时,刷新后退的页面信息,比如后退到首页同时刷新首页的最新数据,这样 ...

  9. 算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法

    一.名称 动态规划法应用 二.目的 1.贪婪技术的基本思想: 2.学会运用贪婪技术解决实际设计应用中碰到的问题. 三.要求 1.实现基于贪婪技术思想的Prim算法: 2.实现基于贪婪技术思想的Dijk ...

  10. 基于vite3+tauri模拟QQ登录切换窗体|Tauri自定义拖拽|最小/大/关闭

    前两天有给大家分享tauri+vue3快速搭建项目.封装桌面端多开窗口.今天继续来分享tauri创建启动窗口.登录窗口切换到主窗口及自定义拖拽区域的一些知识.希望对想要学习或正在学习的小伙伴有些帮助. ...