合并(归并)排序原理及代码实现(c/c++)

2023-05-16

合并排序是采用分治法,先将无序序列划分为有序子序列,再将有序子序列合并成一个有序序列的有效的排序算法。

原理:先将无序序列利用二分法划分为子序列,直至每个子序列只有一个元素(单元素序列必有序),然后再对有序子序列逐步(两两)进行合并排序。合并方法是循环的将两个有序子序列当前的首元素进行比较,较小的元素取出,置入合并序列的左边空置位,直至其中一个子序列的最后一个元素置入合并序列中。最后将另一个子序列的剩余元素按顺序逐个置入合并序列尾部即可完成排序。整体过程如下图:

 两个有序子序列合并的原理如下图:

 步骤

略,上面动图很详细。

代码:递归式实现

#include <malloc.h>
#include <stdlib.h>
void mergesort(int A[],int n)  //合并排序的递归主体
{
    void merge(int A[], int L[], int R[], int l, int r);  //声明merge函数
    if(n>1)    //多于一个元素才需要排序
    {
        int mid=n/2;
        int *left=(int*)malloc(sizeof(int)*mid);
        int *right=(int*)malloc(sizeof(int)*(n-mid));
        for(int i=0;i<mid;i++)
            left[i]=A[i];       //建立临时数组存储左半部分序列
        for(int j=mid;j<n;j++)
            right[j-mid]=A[j];  //建立临时数组存储右半部分序列

        mergesort(left,mid);    //调用自身对左半部分进行合并排序
        mergesort(right,n-mid); //调用自身对右半部分进行合并排序
        merge(A,left,right,mid,n-mid);   //两个有序序列的合并操作,封装为函数
        free(left);
        free(right);
    }
}

void merge(int A[],int L[],int R[],int l,int r)  //两个有序序列L、R合并为A,l,r分别为L,R的长度
{
    int i=0,j=0,k=0;
    while(i<l&&j<r)  //两个子序列首元素做比较,小者取出置入父序列
    {
        if(L[i]<=R[j])
            A[k++]=L[i++];
        else
            A[k++]=R[j++];
    }
    while(i<l)       //将左半部分剩余元素置入父序列
    {
        A[k++]=L[i++];
    }
    while(j<r)       //将右半部分剩余元素置入父序列
    {
        A[k++]=R[j++];
    }
}

改进:非递归式实现

递归式的实现方法,当输入规模增大时,会表现出效率低的缺点。且在排序过程中会不断的开辟临时空间,容易造成内存混乱。

void mergesort(int A[], int n){    //非递归实现。只开辟一个大小与待排序数组相同的存储数组,排序过程中直接在该数组上进行操作。不反复开辟临时数组
	int step;   
	int *p, *q, *t;
	int i, j, k, len1, len2;
	int *temp;  
	step = 1;      //初始步长为1,即将单个元素作为有序子序列进行合并
	p = A;
	q = (int*)malloc(sizeof(int)*n);  //q为临时开辟的空间,用来存储已排序序列,大小为待排序数组的长度
	temp = q;                              //temp与q指向同一段内存,留作最后释放内存空间时使用,因为q指针在后面排序操作中可能会改变指向
	while (step<n)
	{
		i = 0;
		j = i + step;
		k = i;                             //k用作临时数组的下标
		len1 = i + step < n ? i + step : n;   //len1表示有序序列1的下标上限
		len2 = j + step < n ? j + step : n;   //len2表示有序序列2的下标上限
		while (i<n)
		{
			while (i<len1&&j<len2)        //两个子序列首元素做比较,小者取出置入父序列
			{
				q[k++] = p[i]<p[j] ? p[i++] : p[j++];
			}
			while (i<len1)                //将子序列1的剩余元素置入父序列
			{
				q[k++] = p[i++];
			}
			while (j<len2)                //将子序列2的剩余元素置入父序列
			{
				q[k++] = p[j++];
			}
			i = j;                        //j经过自增变为len2,然后赋值给i
			j = i + step;                 //i被赋值为len2,加上步长再赋值给j
			k = i;                        
			len1 = i + step < n ? i + step : n;
			len2 = j + step < n ? j + step : n;
		}
		step *= 2;   //步长翻倍,即将原步长2倍个数的数组元素作为有序子序列进行合并
		t = p;       //t作为临时指针变量,用于交换p和q的指针指向
		p = q;       //将p指针指向经过一轮合并排序后的临时数组
		q = t;       //将q指针指向原数组
	}
	if (A != p){     //如果最终p指针的指向改变为临时数组,则将完成排序的数组拷贝至原数组
		memcpy(A, p, sizeof(int)*n);
	}
	free(temp);
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

合并(归并)排序原理及代码实现(c/c++) 的相关文章

  • 两分钟教你学会用示波器测量串口波特率

    首先接好线 xff0c 黑表笔接地线 xff0c 灰表笔接串口TX数据线 接着打开示波器 xff0c 按下AUTO xff0c 自动测量波形 接着按下AUTO上面的STOP键 xff0c 冻结画面 按下CURSORS xff0c 打开光标模
  • Visual Studio 与Visual C++ 有什么区别

    Visual C 43 43 是 Visual Studio的一个部分 xff0c 此外还有 Visual Basic xff08 VB xff09 Visual C 等 VC 43 43 6 0 是VS6的 VC 43 43 2003 是
  • STM32Cube的串口设置(一)即学即用

    串口系列 STM32Cube的串口设置 xff08 一 xff09 即学即用 STM32Cube的串口设置 xff08 二 xff09 一个串口接收另一个串口发送 串口实战 STM32Cube的串口实战 xff08 一 xff09 GPS
  • C++中构造函数后面接单冒号是什么意思?

    构造函数后 xff0c 接单冒号表示初始化列表 具体形式为 对于class TEST xff0c 存在成员变量int a b c 那么 TEST int x int y a x b y c 0 的效果就是用括号内的值 xff0c 来初始化成
  • 训练神经网络中最基本的三个概念:Epoch, Batch, Iteration

    转载地址 xff1a https zhuanlan zhihu com p 29409502 原作者 xff1a Michael Yuan 作者主页 xff1a https www zhihu com people mikeyuan 今天让
  • 使用makefile编译freeRTOS

    freeRTOS的文件结构 FreeRTOS LabsFreeRTOS Plus 包含freeRTOS 43 的组件和demo项目FreeRTOS 包含内核和demo项目 Source目录 xff1a 三个必须文件list c queue
  • 2013 一路走过

    2013 一路走过 想起当初找工作的时候 xff0c 一个人早上坐火车跑到其他大学的招聘会上去逛一圈 xff0c 了解招聘情况 然后下午又坐火车回学校 记得那天我投了十几份简历出去 xff0c 本打算投着试试 xff0c 没想到回来后有几家
  • 编译vs2008的samples程序总是跳过

    编译vs2008的samples程序总是跳过 xff0c 要配置属性还显示 未能完成操作 未指定的错误 的解决办法 作者 admin 分类 开发问题 发布时间 2013 03 12 09 22 974 浏览数 6 没有评论 文章转自王牌软件
  • MFC 用户界面线程:界面线程的退出 窗口关闭的流程

    原文链接 xff1a http wenku baidu com link url 61 6CFkWbLOeFgNoUsJniCX3ksw6 RztxMr9Z e6t7uu3e vV7UTKThUEkyRkq8IXwxIw5qYctN8gIx
  • MFC用户界面多线程实例2

    以下是 MFC 用户界面线程相关知识 由于用户界面线程含有自己的消息循环 xff0c 可以出来 Windows 消息 xff0c 并可创建和管理诸如窗口和控件等用户界面 元素 因此 xff0c 这 种线程较工程线程更为复杂 创建用户界面线程
  • 反汇编定位代码崩溃位置_1

    原帖 xff1a http blog csdn net gwzz1228 article details 9045853 利用map xff0c cod文件定位崩溃代码行 利用vs2010 新建一个空的控制台项目 xff0c 添加文件gtg
  • 反汇编定位代码崩溃位置_3

    原帖 xff1a http blog sina com cn s blog 141f234870102van8 html win7 43 vs2010通过map文件和cod文件找到崩溃的代码行 2015 01 11 11 31 04 转载
  • 反汇编定位代码崩溃位置_4

    原帖 xff1a http blog csdn net xiao article details 23177577 GDB如何从Coredump文件恢复动态库信息 标签 xff1a GDBcoredumpso调试动态库 2014 04 08
  • STM32Cube的串口设置(二)一个串口接收另一个串口发送

    串口系列 STM32Cube的串口设置 xff08 一 xff09 即学即用 通过串口设置第一部分大家应该基本会使用单个串口进行收发了 所以本次介绍通过串口进行转发 适合情景为一个串口设备波特率为38400 xff0c 但是接收模块仅支持1
  • C链表反转

    节点 struct Note int value Note pNext typedef struct Note PList 生成一个链表 Note GenerateList 输出一个链表 void PrintList Note pHead
  • PMP考试重点知识

    第一章 引论 前三章 是整个知识体系的支撑框架 xff0c 每次考试中都会考到 xff0c 但是一般在15道题左右 xff0c 前 三章 学不好后面的章 节很难理解透彻 1 项目的特点 xff1f 2 什么是项目管理 xff1f 3 项目和
  • pcb焊接技巧

    焊接的先后次序 要想更高效 可靠地焊好一块板子 xff0c 是要遵循一定的原则 xff08 如 先小后大 xff09 的 xff0c 不可乱来 xff0c 更不是看哪个元件顺眼就焊哪个 一般我拿到一块板子后的处理流程是 xff1a 打印 P
  • js中通过document获取标签节点

    使用id名表示标签 xff0c 不够严谨 在html语法中 xff0c id名随便起 xff0c 可以是js中的关键字 xff0c 但是在js中使用id代表标签 xff0c 就不能使用关键字 xff0c 所以我们需要一种更加严谨的方式获取标
  • 安装ubuntu-desktop

    目录 安装ubuntu desktop 解决root登录受限 安装远程访问软件 方法一 xff1a 安装vnc4server 方法二 xff1a Teamviwer安装 传送门 推荐 正文 回到顶部 安装ubuntu desktop 复制代

随机推荐