归并排序

归并排序与原地归并排序 归并排序的思想:假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;再两两归并,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2-路归并排序。其核心操作是将一个一维数组的前后相邻的两个子序列合并为一个有序序列。下图为一个2路归并排序的例子。 阅读详情

归并排序就是将要排序的数组分成两部分,每一部分都排好序,再将这两部分归并为一个数组,每一部分的排序又采用归并排序。

归并排序按照空间的使用上来分主要分为两种:普通归并和原地归并。按照归并的方向可以分为自顶向下归并和自底向上归并。

1.普通归并:需要创建一个新的数组,将两个已经排好序的数组归并到这个新数组中。

2.原地归并:

归并排序最主要的一个函数就是merge,函数接口如下:

void merge(int data[], int start, int mid, int end);

这个函数负责将data数组中start~mid子数组和mid~end子数组进行原地归并,这个函数的前提条件是两个子数组都已经排好序。下面是这个函数的具体实现代码:

//[start, mid), [mid, end)
void merge( int data[], int start, int mid, int end )
{

    assert( data != NULL && start <= mid && mid <= end );
    //如果一共只有一个元素,则不用合并
    if ( start == mid && mid == end )
        return ;
    //辅助数组
    int temp[end];
    int i = start, j = mid, k, n;
    //将要合并的元素拷贝到辅助数组中
    for ( k = start; k < end; k++ )
        temp[k] = data[k];
    //
    for ( k = start; k < end; k++ )
    {
        //i>=mid说明前半部分先被合并完,直接将后半部分剩余的元素接到data后面
        if ( i >= mid )
            data[k] = temp[j++];
        //i>=mid说明后半部分先被合并完,直接将前半部分剩余的元素接到data后面
        else if ( j >= end )
            data[k] = temp[i++];
        //两者中选择较小的放到data中
        else if ( temp[i] > temp[j] )
            data[k] = temp[j++];
        else
            data[k] = temp[i++];
    }
}
归并排序最主要的函数就是merge函数,所以保证将merge函数写正确是非常重要的,写归并排序的时候可以先写一个merge函数,然后模拟几个环境测试一下,测试没有问题之后再进行下一步,否则如果一次性将整个归并算法全部写出,出现问题之后,因为递归层数比较多,找起来很麻烦。写好了merge函数,不管是自顶向下还是自底向上归并都只是对merge函数不同方式的调用而已。

3.归并排序的两种方向:

为了直观的理解自顶而下和自底向上,我放了一张图。

自顶而下顾名思义:就是从最上面到最下面了,从这幅图来看,最上面就是a[0...15],就是整个数组了。而最下面就是每一个元素了。所以自顶而下归并就是先从数组的整体出发,将数组全部元素看做一个整体,将这个整体分成两部分,并且假设每一部分都已经排好序了,所以只需要将这两部分直接归并,但是为了保证这两个部分都已经排好序,我们又需要为每一部分使用归并排序排序,在对图中第二层的每个子数组调用归并排序时,又会将图中第二层的数组分解为第三层,然后分别调用归并排序,经过这样几轮递归后,直到每个子数组都只剩下一个元素递归才开始回溯。回溯完成,排序也就完成了。这就是自顶而下。

自底向上:与自顶向下刚好相反,先从子数组依赖树的最低端出发,保证在为一个数组排序时,它的两个部分都已经被排好序,(自顶而下是假设已经排好序,两个不一样。)。

3.1自顶向下代码实现:

因为自顶向下归并要使用递归,传递参数时要向下一层递归传递一些信息,为了保证接口的统一性,所以特别增加了内部函数_sort来完成排序的主要工作。

void _sort(int data[], int start, int end )
{
    int mid = start + ( end-start )/2;
    //如果要排序的数字少于等于1个,直接返回
    if ( start >= end - 1 )
    {
        //printf( "skip --->  start = %d, mid = %d, end = %d\n", start, mid, end );
        return ;
    }
    _sort(data, start, mid );
    _sort(data, mid, end );
    //printf( "start = %d, mid = %d, end = %d\n", start, mid, end );
    merge(data, start, mid, end );
   
}
//自顶向下的归并排序
void merge_sort( int data[], int size )
{
    assert( data != NULL & size > 0 );
    _sort( data, 0, size );
}

3.2自底向上代码实现

void merge_sort( int data[], int size )
{
    assert( data != NULL && size > 0 );
    int i, j;
    for ( i = 1; i < size; i = i+i )
        for ( j = 0; j < size-i; j += i+i )
            merge( data, j, j+i, ( j+i+i )<( size-1 )?( j+i+i ):( size ) );
}



一种基于数据块交换的快速稳定原地归并算法① (2004年) 与其它排序算法相比,二路归并最适合于对2个有序子表进行排序。归并长度分别为m和n的2个有序子表,经典算法有2种。第一种算法完成归并需要附加O(m+n)的空间,O(m+n)次比较和移动。第二种算法是原地的,但完成归并需要O(m+n)次比较和O(m×n)次移动。提出了一种基于块交换的快速稳定原地二路归并算法。实验证明,该算法与以前的原地算法相比,大大降低了元素的移动次数。 立即下载

相关推荐

微信小程序利用Echarts加载中国地图的步骤

微信小程序如何利用Echarts加载地图?可按照如下四个步骤进行。(阅读时间大概3分钟)。

成都都成 5279

【一文吃透归并排序】基本归并·原地归并·自然归并 C++

不从整体开始切分,而是一开始把每一个元素当成一个列表,然后,自底向上地合并相邻的列表,重复利用开始的那张图。

六根胡子 1872

【TiktokAPI】Tiktok直播API与实时互动功能开发完全指南

Tiktok直播API允许开发者创建、管理直播,并实现各种互动功能。/*** 获取Tiktok直播API访问令牌* @param {string} client_id - 应用ID* @param {string} client_secret - 应用密钥* @param {string} code - 授权码* @param {string} redirect_uri - 重定向URI* @returns {Promise<object>} 访问令牌响应*/try {}),

Mageia的专栏 3203

原地归并排序

原地归并排序相比于普通归并排序,不需要开拓额外空间

随便记点东西 5881

U8 API接口开发踩过的坑

U8 API接口开发踩过的坑

haiyang5233233的专栏 1657

光斑大小控制【ZEMAX操作数】

在使用Zemax优化光学系统时,对成像的聚焦光斑大小进行限制,即弥散斑的大小; 一、RSCE(质心RMS光斑半径):二、RSCH(光线RMS光斑半径):

yh的博客 7870

In-place Merge Sort (原地归并排序)

原文链接:http://blog.ibread.net/345/in-place-merge-sort/ 一般在提到Merge Sort时,大家都很自然地想到Divide-and-Conqure, O(nlgn)的时间复杂度以及额外的O(n)空间。O(n)的

zentropy的专栏 3726

《QGIS快速入门与应用基础》230:添加图例工具

本文系统讲解QGIS图例制作的核心方法与优化技巧。首先强调图例与地图框的绑定逻辑,提出三种绑定状态及适用场景。详细拆解三种图例添加方法:布局工具栏一键添加法(新手首选)、菜单栏添加法和右键快捷创建法,并给出单地图框和多地图框两种典型场景的规范技巧。重点解决新手常见的图例杂乱、样式不规范、内容脱节等问题,帮助用户从基础图例制作进阶到符合行业标准的专业图例设计。通过分步操作图示和实用技巧,使读者能够快速掌握图例创建的核心流程与优化方法。

LuckyHanMo的博客 552

归并排序详解

摘要:归并排序是我们常用的八大排序中的一种,其排序思路中和快速排序算法一样使用到了递归的思想,同时在归并排序中还用到了一个算法,就是有序数组合并算法。配合递归与有序数组合并算法,归并排序能够高效且稳定的完成排序,归并排序的优点在于其时间复杂度低,稳定性高,但是缺点也是有的,那就是空间复杂度很高。

云杉木屋 2万+

Simulink仿真模块 - Signal Conversion

目录 说明 实例 创建总线信号的连续副本 ​将虚拟总线转换为非虚拟总线​ 将非虚拟总线转换为虚拟总线 将Muxed信号转换为矢量 模块特性 Signal Conversion:将信号转换为新类型,而不改变信号值 在仿真库中的位置为: Simulink / Signal Attributes HDL Coder / Signal Attributes 模型为: 说明 Signal Conversion模块可将信号从一种类型转换为另一种类型。要选择要...

jk_101的博客 3421

【GameFramework框架内置模块】10、本地化(Localization)

本地化(Localization),也就是我们所说的不同地区的语言适配,比如说中文版“你好”,英文版是“Hello”。GameFramework在本地化方面,不仅支持文本的本地化,还支持任意资源的本地化,比如说游戏中释放烟花的特效也可以做出不同地区的版本,使得中文版烟花里面的“新年好”字样的特效,在英文版里面是“Happy New Year”字样的特效。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2305

常见排序算法之归并排序——归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法 (Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序 列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。...

保护小周ღ的博客 2403

提交 ieee 手稿出现:Do not include the Reviewer PDF with my submission 怎么办

IEEE投稿Reviewer PDF选项说明 投稿时出现的"Do not include the Reviewer PDF with my submission"选项控制是否附带评审专用PDF文件。Reviewer PDF是系统自动生成包含所有投稿材料的完整PDF,用于同行评审。建议保持默认不勾选状态,除非确认编辑部不需要该文件,否则可能影响审稿流程。勾选表示不附带此PDF,不勾选则会正常生成并提交该评审文件。

ZhangJiqun&191cm&85kg 2215

归并排序与自然归并排序

1.归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题2.时间复杂度:O(N * logN)3.空间复杂度:O(N)4.稳定度:稳定.1.这玩意的思路相比于其它排序其实特别恶心,在生产环境中非常不建议使用,你的项目组成员可能会骂街(除非是这种情况:就比如你的数据结构老师心血来潮让你讲这个,那你也没办法...)2.时间复杂度:遍历了一次:O(n)3.空间复杂度:O(n)

asdssadddd的博客 1149

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

归并排序-自底向上的归并排序算法

归并排序 归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 算法描述 分解: 将原序列分解成length长度的若干子序列 求解子问题: 将相邻的两个子序列调用Merge算法合并成一个有序子序列 合并: 由于整个序列存放在数字a中,排序过程是就地进行的,合并步骤不需要执行

qq_45727976的博客 2990

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

归并排序的一些拓展应用

归并排序的一些拓展问题, 包含小和问题, 逆序对问题, 翻转对问题, 区间和的个数问题.

trong_ 的烂笔头 870

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

排序算法 归并排序(普通归并排序、自然归并排序)

自然归并排序:对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段有{4,8},{3,7},{1,5,6},{2}.用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段.然后将相邻的排好序的子数组段两两合并,构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).继续合并相邻排好序的子数组段,直至整个数组已排好序。(1)申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列。

qq_36511401的博客 1万+

归并排序及模板

文章目录归并排序理解归并排序模板 归并排序理解 归并排序的主要操作如下: (1)分解。把初始序列分成长度相同的左、右两个子序列,然后把每个子序列再分成更小的两个子序列,直到子序列只包含一个数。这个过程用递归实现。 (2)求解子问题,对子序列排序。最底层的子序列只包含一个数,其实不用排序。 (3)合并。归并两个有序的子序列,这是归并排序的主要操作。比如下面举例,把a[ ]分成两个子序列,比较后存进b...

ker的博客 2050

链表的归并排序

链表的归并排序是一种高效、稳定的排序算法,非常适合链表这种数据结构。通过分治思想,将链表不断分割并合并,实现了对链表的排序。

2401_86909484的博客 1174

数组排序之归并排序

归并排序(Merge Sort)是数组排序算法中一种常见的算法,其主要思想为经典的“分治思想”。本文将介绍数组排序算法中的归并排序,并介绍其相关应用。

山阴少年 2487

归并排序算法、多路归并排序

base case:if(left>=right) return; 归并排序左半边,归并排序右半边,合并 void merge_sort(vector<int> &nums,vector<int> reg,int start,int end){ if(start>=end) return ; int mid=(end-start)/2+start; int start1=start,end1=mid; int start2=mid+

大灰狼吃树皮 4003
上一篇: 发现了一个gdb的小bug
下一篇: 【CSAPP阅读笔记】之信息的存储
Findway_
博客等级 码龄10年 36粉丝 117原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值