C语言实现归并排序(Merge Sort)

目录

一、递归实现归并排序

1. 归并排序的基本步骤

2.动图演示

3.基本思路 

4.代码

 二、非递归实现

1.部分代码

2.代码分析

修正后代码:

 归并过程打印

性能分析

 复杂度分析


归并排序是一种高效的排序算法,采用分治法(Divide and Conquer)的一个非常典型的应用。归并排序的基本思想是将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

一、递归实现归并排序

1. 归并排序的基本步骤

  1. 分解:将数组分解成两个较小的子数组,直到子数组的大小为1。
  2. 递归进行排序并合并:递归地对子数组进行排序,并将已排序的子数组合并成一个大的有序数组,直到合并为1个完整的数组。

2.动图演示

3.基本思路 

归并排序是采用分治法的一个非常典型的应用。其基本思想是:将已有序的子序合并,从而得到完全有序的序列,即先使每个子序有序,再使子序列段间有序。

那么如何得到有序的子序列呢?当序列分解到只有一个元素或是没有元素时,就可以认为是有序了,这时分解就结束了,开始合并。

4.代码

void _MergSort(int* a, int left,int right,int* tmp)
{if (left >= right)return;int mid = left + (right - left) / 2;_MergSort(a, left, mid, tmp);_MergSort(a, mid+1, right, tmp);int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int i = left;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1<=end1){tmp[i++] = a[begin1++];}while (begin2<=end2){tmp[i++] = a[begin2++];}for (int j = 0; j <= right; j++){a[j] = tmp[j];}
}void MergSort(int* a, int n)
{int* tmp = (int*)malloc(n * sizeof(int));if (tmp == NULL){perror("malloc fail");exit(-1);}_MergSort(a,0, n-1, tmp);free(tmp);
}

 二、非递归实现

归并排序的非递归算法并不需要借助栈来完成,我们只需要控制每次参与合并的元素个数即可,最终便能使序列变为有序:

1.部分代码

void MergSortNonF(int* a, int n)
{int* tmp = (int*)malloc(n * sizeof(int));if (tmp == NULL){perror("malloc fail");exit(-1);}int gap = 1;while (gap < n){for (int j = 0; j < n; j += 2 * gap){//*****注意边界处理*******int begin1 = j, end1 = j + gap - 1;int begin2 = j + gap, end2 = j + gap * 2 - 1;printf("[%d %d] [%d %d]", begin1, end1, begin2, end2);int i = j;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}}printf("\n");memcpy(a, tmp, n * sizeof(int));gap *= 2;}free(tmp);tmp = NULL;
}

2.代码分析

这是一个有问题的代码,当我们存放的数据是2的次方时,可以正常排序,为了便于观察,我们把它的下标给打印下来

如果我们存放的数据不是2的次方个就会出现一些越界。


情况一:第二组部分越界
 当最后一个小组进行合并时,第二个小区间存在,但是该区间元素个数不够gap个,这时我们需要在合并序列时,对第二个小区间的边界进行控制。

情况二:第二组全部越界
 当最后一个小组进行合并时,第二个小区间不存在,此时便不需要对该小组进行合并。

情况三:第一组end1越界
 当最后一个小组进行合并时,第二个小区间不存在,并且第一个小区间的元素个数不够gap个,此时也不需要对该小组进行合并。(可与情况二归为一类)

只要把控好这三种特殊情况,写出归并排序的非递归算法便轻而易举了。

修正后代码:

void MergSortNonF(int* a, int n)
{int* tmp = (int*)malloc(n * sizeof(int));if (tmp == NULL){perror("malloc fail");exit(-1);}int gap = 1;while (gap < n){for (int j = 0; j < n; j += 2 * gap){//*****注意边界处理*******int begin1 = j, end1 = j + gap - 1;int begin2 = j + gap, end2 = j + gap * 2 - 1;//第一组越界if (end1 >= n){printf("[%d %d]", begin1,n-1);break;}//第二组全部越界if (begin2 >= n){printf("[%d %d]", begin1, end1);break;}//第二组部分越界,越界之前的那一部分依然要归if (end2 >= n){//修正end2end2 = n - 1;}printf("[%d %d] [%d %d]", begin1, end1, begin2, end2);int i = j;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}//归并那一部分拷贝哪一部分memcpy(a+j, tmp+j, (end2-j+1)* sizeof(int));}printf("\n");//memcpy(a, tmp, n * sizeof(int));gap *= 2;}free(tmp);tmp = NULL;
}

 归并过程打印

性能分析

 复杂度分析

  • 时间复杂度:归并排序的时间复杂度为O(n log n),其中n是数组的长度。这主要是由于归并排序将问题分解为两个子问题(分解),递归地解决它们(递归),然后将解决方案合并(合并)。
  • 空间复杂度:归并排序的空间复杂度为O(n),其中n是数组的长度。这是因为归并排序在合并过程中需要与原数组同样大小的额外空间来存放临时数组。

归并排序是稳定的排序算法,即相等的元素在排序后的序列中仍然保持原来的顺序。这个特性在某些应用中非常重要。

 


如有错误,劳烦各位指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/433001.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【芋道源码】gitee很火的开源项目pig——后台管理快速开发框架使用笔记(微服务版之本地开发环境篇)

后台管理快速开发框架使用笔记&#xff08;微服务版之本地开发环境篇&#xff09; 后台管理快速开发框架使用笔记&#xff08;微服务版之本地开发环境篇&#xff09; 后台管理快速开发框架使用笔记&#xff08;微服务版之本地开发环境篇&#xff09;前言一、如何获取项目&#…

计算机毕业设计宠物领养网站我的发布领养领养用户信息/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序

目录 1.课题背景 2.课题意义 ‌ 3.技术介绍 4.技术性需求 4.1后端服务‌&#xff1a; 4.2 前端展示‌ 5.数据库设计‌&#xff1a; 6.系统性能‌&#xff1a; 7.安全性‌&#xff1a; 8. 功能介绍&#xff1a; 9. 部分代码 1.课题背景 近年来&#xff0c;随着宠物饲养数量…

2024年9月25日--- Spring-IOC 1

一 Spring的概要 1.1 简介 Spring&#xff0c;春天的意思&#xff0c;意指给软件行业带来春天。2002年&#xff0c;Rod Jahnson首次推出了Spring框架雏形interface21框架。2004年3月24日&#xff0c;Spring框架以interface21框架为基础&#xff0c;经过重新设计&#xff0c;发…

《深度学习》—— ResNet 残差神经网络

文章目录 一、什么是ResNet&#xff1f;二、残差结构&#xff08;Residual Structure&#xff09;三、Batch Normalization&#xff08;BN----批归一化&#xff09; 一、什么是ResNet&#xff1f; ResNet 网络是在 2015年 由微软实验室中的何凯明等几位大神提出&#xff0c;斩获…

linux信号 | 学习信号三步走 | 全解析信号的产生方式

前言&#xff1a;本节内容是信号&#xff0c; 主要讲解的是信号的产生。信号的产生是我们学习信号的第二个阶段。 我们已经学习过第一个阶段——信号的概念与预备知识&#xff08;没有学过的友友可以查看我的前一篇文章&#xff09;。 以及我们还没有学习信号的第三个阶段——信…

89个H5小游戏源码

下载地址&#xff1a;https://download.csdn.net/download/w2sft/89791650 亲测可用&#xff0c;代码完整&#xff0c;都是htmljs&#xff0c;保存到本地即可。 游戏截图&#xff1a;

Universal Link配置不再困扰,Xinstall来帮忙

在移动互联网时代&#xff0c;App的推广和运营至关重要。而Universal Link作为一种能够实现网页与App间无缝跳转的技术&#xff0c;对于提升用户体验、引流至App具有显著效果。今天&#xff0c;我们就来科普一下Universal Link的配置方法&#xff0c;并介绍如何通过Xinstall这款…

TypeScript 设计模式之【备忘录模式】

文章目录 备忘录模式&#xff1a;时光机器的魔法备忘录模式的奥秘备忘录模式有什么利与弊?如何使用备忘录模式来优化你的系统代码实现案例备忘录模式的主要优点备忘录模式的主要缺点备忘录模式的适用场景总结 备忘录模式&#xff1a;时光机器的魔法 想象一下&#xff0c;如果…

25 基于51单片机的温度电流电压检测系统(压力、电压、温度、电流、LCD1602)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;通过DS18B20检测温度&#xff0c;滑动变阻器连接数模转换器模拟电流、电压&#xff0c;通过LCD1602显示&#xff0c;程序里设置温度阈值为40&#xff0c;电流阈值为60&am…

万博智云CEO王嘉在华为全联接大会:以创新云应用场景,把握增长机遇

一、大会背景 2024年9月19-21日&#xff0c;第九届华为全联接大会将在上海世博展览馆和上海世博中心举办。作为华为的旗舰盛会&#xff0c;本次大会以“共赢行业智能化”为主题邀请了众多思想领袖、商业精英、技术专家、合作伙伴、开发者等业界同仁&#xff0c;从战略、产业、…

Nginx基础详解3(nginx.conf核心代码讲解、常用命令解析、Nginx日志切割)

续Nginx基础详解2&#xff08;首页解析过程、进程模型、处理Web请求机制、nginx.conf语法结构&#xff09;-CSDN博客 目录 8.nginx.conf核心代码 8.1错误日志 8.1.1第一列&#xff1a; 8.1.2第二列&#xff1a; 8.1.3第三列&#xff1a; 8.2 #pid 8.3http模块&#xff…

A开头的词根词缀:-ate+a-+ab\abs+ab\c\d\f\g\n\p\r\s\t+ad+amph+an+ana+ante+anti+anthrop+

ate -ate,它是英语单词中的后缀词缀。它加在词根或词干上分三种词性。 首先第一种词性adj.(形容词)&#xff0c;它主要加缀在名词词根或词干上构成的形容词&#xff1a;……的&#xff0c;有……的&#xff0c;像……的&#xff0c;For example:accurate(adj.正确的&#xff…

如何实现全行业证照一站式结构化识别?Textln企业资质证照识别上线!

企业经营活动中&#xff0c;资质证书是证明企业具备某项行业准入的必要证件。但企业资质证书种类繁多&#xff0c;各行各业的资质证书都有差异&#xff0c;同一行业、不同地区出具的资质证书版式也各不相同&#xff0c;通过传统标注训练的方式难以全量覆盖各类企业资质证照的识…

【JAVA开源】基于Vue和SpringBoot的墙绘产品展示交易平台

本文项目编号 T 049 &#xff0c;文末自助获取源码 \color{red}{T049&#xff0c;文末自助获取源码} T049&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

机器人顶刊IEEE T-RO发布无人机动态环境高效表征成果:基于粒子的动态环境连续占有地图

摘要&#xff1a;本研究有效提高了动态环境中障碍物建模的精度和效率。NOKOV度量动作捕捉系统助力评估动态占用地图在速度估计方面的性能。 近日&#xff0c;上海交通大学、荷兰代尔夫特理工研究团队在机器人顶刊IEEE T-RO上发表题为Continuous Occupancy Mapping in Dynamic …

【C语言】手把手带你拿捏指针(完)(指针笔试、面试题解析)

文章目录 一、sizeof和strlen的对⽐1.sizeof2.strlen3.sizeof与strlen对比 二、数组和指针笔试解析1.一维数组2.字符、字符串数组和字符指针代码1代码2代码3代码4代码5代码6 3.二维数组4.总结 三、指针运算笔试题解析代码1代码2代码3代码4代码5代码6 一、sizeof和strlen的对⽐ …

线性跟踪微分器TD详细测试(Simulink 算法框图+CODESYS ST+博途SCL完整源代码)

1、ADRC线性跟踪微分器 ADRC线性跟踪微分器(ST+SCL语言)_adrc算法在博途编程中scl语言-CSDN博客文章浏览阅读784次。本文介绍了ADRC线性跟踪微分器的算法和源代码,包括在SMART PLC和H5U平台上的实现。文章提供了ST和SCL语言的详细代码,并讨论了跟踪微分器在自动控制中的作用…

排序--希尔排序

希尔排序介绍 希尔排序核心思想就是:1,分组;2,直接插入排序:越有序越快 希尔排序就是多次利用直接插入排序的一个排序算法. 希尔排序的算法思想:间隔式分组,利用直接插入排序让组内有序,然后缩小分组再次排序,直到组数为1希尔排序的理论基础就是直接插入排序越有序越快; 希尔排…

Redis-----通用命令(keys, exists, del, expire, ttl, type)

通用命令 一. 前言.1.1 通用命令1.2 Redis常用的数据类型1.2.1 String&#xff08;字符串&#xff09;1.2.2 List&#xff08;列表&#xff09;1.2.3 Set&#xff08;集合&#xff09;1.2.4 Hash&#xff08;哈希&#xff09;1.2.5 Zset&#xff08;有序集合&#xff09; 二. 通…

通过 OpenAI API 实测 o1 模型(附源码)

9.11 与 9.9 哪个大? 还记得之前给大家演示的幻觉问题么&#xff1f; 用 gpt4 系列模型提问“9.11 与 9.9 哪个大?” 大家可以回顾一下&#xff0c;即使引导了 COT 的思路&#xff0c;但是 gpt4 还是一本正经的胡说八道。 如今&#xff0c;o1 已经完美解决数学、逻辑推理方…