[排序算法] 归并排序 (C++)
归并排序解释
归并排序 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++)的更多相关文章
- 经典排序算法 - 归并排序Merge sort
经典排序算法 - 归并排序Merge sort 原理,把原始数组分成若干子数组,对每个子数组进行排序, 继续把子数组与子数组合并,合并后仍然有序,直到所有合并完,形成有序的数组 举例 无序数组[6 2 ...
- 数据结构和算法(Golang实现)(23)排序算法-归并排序
归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...
- 使用 js 实现十大排序算法: 归并排序
使用 js 实现十大排序算法: 归并排序 归并排序 refs js 十大排序算法 All In One https://www.cnblogs.com/xgqfrms/p/13947122.html ...
- java泛型中使用的排序算法——归并排序及分析
一.引言 我们知道,java中泛型排序使用归并排序或TimSort.归并排序以O(NlogN)最坏时间运行,下面我们分析归并排序过程及分析证明时间复杂度:也会简述为什么java选择归并排序作为泛型的排 ...
- js 实现排序算法 -- 归并排序(Merge Sort)
原文: 十大经典排序算法(动图演示) 归并排序 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得 ...
- javascript排序算法-归并排序
归并排序 概念:归并排序是一种分治算法.其思想是将原始数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组归并成较大的数组,直到最后只有一个排序完毕的大数组. 时间复杂度: O(nlogn) ...
- 八大排序算法——归并排序(动图演示 思路分析 实例代码java 复杂度分析)
一.动图演示 二.思路分析 归并排序就是递归得将原始数组递归对半分隔,直到不能再分(只剩下一个元素)后,开始从最小的数组向上归并排序 1. 向上归并排序的时候,需要一个暂存数组用来排序, 2. 将 ...
- 排序算法-归并排序(Java)
package com.rao.sort; import java.util.Arrays; /** * @author Srao * @className MergeSort * @date 201 ...
- 疯子的算法总结(六) 复杂排序算法 ① 归并排序 merge_sort()
归并排序采取了分治的思想,每次分别排左半边和右半边,不断递归调用自己,直到只有一个元素递归结束,开始回溯,调用merge函数,合并两个有序序列,再合并的时候每次给末尾追上一个最大int这样就不怕最后一 ...
- JavaScript排序算法——归并排序
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
随机推荐
- Elasticsearch7.6.2 RestHighLevelClient查询用法 must should(and or 关系)
1. 引入jar <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId&g ...
- idea每次换行后光标都跑到最左边问题
最进用idea时发现每次换行之后一段时间光标会自动跑到最左边,默认把我的首行空格删掉了 IDEA版本为:IntelliJ IDEA 2020.2.3 x64
- kubeadm init 命令执行流程
- MongoDB 单实例节点主机的用户和权限一般操作步骤
步骤总结: 1.先正常启动 2.创建用户,创建数据库病授权用户 3.关闭程序,开启安全,然后启动 4.使用账号和密码连接 按未开启认证的方式(配置文件中没开启安全选项并且启动命令中不添加 --auth ...
- .NET 反向代理 YARP 跨域请求 CORS
使用过 nginx 的小伙伴应该都知道,这个中间件是可以设置跨域的,作为今天的主角,同样的 反向代理中间件的 YARP 毫无意外也支持了跨域请求设置. 有些小伙伴可能会问了,怎样才算是跨域呢? 在 H ...
- Linux 宝塔部署 ASP.NET Core 应用
第一步,发步应用 我这是一个API 应用和 MVC 应用 设置,服务器上要运行的端口 API 端口5000 MVC 端口5001 打包文件夹,发步 1.桌面新建俩个文件夹 2.右键项目发步,选中iis ...
- SQLServer配置开启TCP/IP连接
一 先启用SQLServer的TCP/IP协议 1.1 打开SQLServer配置管理器 1.2 启用TCP/IP 二 设置SQLServer端口 2.1 双击TCP/IP,弹出属性设置框 2.2 将 ...
- 关于history.back()、history.go()回退但无法刷新页面的问题
window.history.back(); 这样确实可以做到后退的功能,但是项目中,常常并不只是后退就能完成需求,往往需要在后退的同时,刷新后退的页面信息,比如后退到首页同时刷新首页的最新数据,这样 ...
- 算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
一.名称 动态规划法应用 二.目的 1.贪婪技术的基本思想: 2.学会运用贪婪技术解决实际设计应用中碰到的问题. 三.要求 1.实现基于贪婪技术思想的Prim算法: 2.实现基于贪婪技术思想的Dijk ...
- 基于vite3+tauri模拟QQ登录切换窗体|Tauri自定义拖拽|最小/大/关闭
前两天有给大家分享tauri+vue3快速搭建项目.封装桌面端多开窗口.今天继续来分享tauri创建启动窗口.登录窗口切换到主窗口及自定义拖拽区域的一些知识.希望对想要学习或正在学习的小伙伴有些帮助. ...