【排序】归并排序(C语言实现)
文章目录
- 1. 递归版的归并排序
- 1.1 归并排序的思想
- 2. 递归版的归并排序的实现
- 2. 非递归版的归并排序
1. 递归版的归并排序
1.1 归并排序的思想
归并排序(MERGE - SORT)是建立在归并操作上的一种有效的排序算法, 该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:


这里我们先介绍一下递归版本的归并排序的思想:
- 我们需要先创建一个临时数组,用来将需要排序的数组归并到这个临时数组里面去,然后再将这个数组拷贝到原数组中去,这样就完成了排序的过程。
2. 递归版的归并排序的实现
具体实现方式如下:
void Sub_MergeSort(int* a, int* tmp, int begin, int end)
{if (begin >= end - 1) // 我控制的是左闭右开区间return;int key = (begin + end) / 2;// [left,key + 1) [key,end) 左闭右开的空间一定要控制好int begin1 = begin, end1 = key;int begin2 = key, end2 = end;Sub_MergeSort(a, tmp, begin1, end1);Sub_MergeSort(a, tmp, begin2, end2);// 归并过程int indix = begin;while (begin1 < end1 && begin2 < end2){if (a[begin1] <= a[begin2]){tmp[indix++] = a[begin1++];}else{tmp[indix++] = a[begin2++];}}while (begin1 < end1){tmp[indix++] = a[begin1++];}while (begin2 < end2){tmp[indix++] = a[begin2++];}// 将tmp数组中的元素拷贝到元素中memmove(a + begin, tmp + begin, (end - begin)*sizeof(int));
}void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail\n");return;}// 因为这里开一次空间就够用了,所以递归过程我们还是要写成一个子函数来完成Sub_MergeSort(a, tmp, 0, n);free(tmp);tmp = NULL;
}
2. 非递归版的归并排序
所以在平时我们要使用归并排序时,使用递归版的完全够用了。但由于现在还在学习阶段,所以掌握一下非递归版的归并排序还是有必要的。
把递归改成非递归,这个怎么处理呢?可以像我们之前讲的快速排序的非递归一样使用栈吗?
这里实现非递归的归并排序使用栈其实不是很好的方式,反而会使问题变复杂。

所以我们就得想其他办法:
可以这样:

但是这里需要注意两种情况:

这里不控制好边界的话,很容易就造成越界了,这里我分享两种控制边界的方式,细节我写在注释里了:
方式一:
// 归并排序 -- 非递归
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail\n");return;}int gap = 1;while (gap < n){for (int i = 0;i < n;i = 2 * gap + i){int begin1 = i, end1 = i + gap - 1; // 定义每次归并时的第一组数据int begin2 = i + gap, end2 = i + 2 * gap - 1; // 定义每次归并时的第二组数据if (begin2 >= n) // 如果第二组不存在了,这一趟就不用归并了{break;}if (end2 >= n) // 如果存在第二组,但第二组的末尾越界了,应该调整一下{end2 = n - 1;}// 归并过程int indix = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[indix++] = a[begin1++];}else{tmp[indix++] = a[begin2++];}}while (begin1 <= end1){tmp[indix++] = a[begin1++];}while (begin2 <= end2){tmp[indix++] = a[begin2++];}// 将tmp数组拷贝回原数组memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(int));}gap *= 2;}free(tmp);tmp = NULL;
}
方式二:
void MergeSortNonR2(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail\n");return;}int gap = 1;while (gap < n){int j = 0;for (int i = 0;i < n;i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;// end1 >= n - 1 和begin2 >= n 都代表没有第二组,所以第二组就不用参与归并过程if (end1 >= n){end1 = n - 1;// 此时begin2和end2一定是越界的// 我们手动让这段空间不存在begin2 = n;end2 = n - 1;}else if (begin2 >= n){// 我们手动让这段空间不存在begin2 = n;end2 = n - 1;}else if (end2 >= n) // 此时end1 和 begin2都没有越界{end2 = n - 1;}// 归并过程while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}}memcpy(a, tmp, sizeof(int) * n);gap *= 2;}free(tmp);tmp = NULL;
}
相关文章:
【排序】归并排序(C语言实现)
文章目录 1. 递归版的归并排序1.1 归并排序的思想2. 递归版的归并排序的实现 2. 非递归版的归并排序 1. 递归版的归并排序 1.1 归并排序的思想 归并排序(MERGE - SORT)是建立在归并操作上的一种有效的排序算法, 该算法是采用分治法(Divide a…...
127. 单词接龙
和433.最小基因变化这道题一样的解法。 https://blog.csdn.net/qq_43606119/article/details/135538247 class Solution {public int ladderLength(String beginWord, String endWord, List<String> wordList) {Set<String> cnt new HashSet<>();for (int …...
计算机算法贪心算法
贪心算法(Greedy Algorithm)是一种常见的算法思想,它在每一步选择当前状态下最优的解决方案,从而希望最终能够达到全局最优解。 贪心算法的基本思路是每一步都选择当前状态下的局部最优解,而忽略了当前选择所带来的影…...
基于css实现动画效果
介绍 本文将会基于css,实现各种动画效果,接下来会从简单几个例子入手。 案例 三颗球 <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" /><title>React App</title><style>…...
18.将文件上传至云服务器 + 优化网站的性能
目录 1.将文件上传至云服务器 1.1 处理上传头像逻辑 1.1.1 客户端上传 1.1.2 服务器直传 2.优化网站的性能 2.1 本地缓存优化查询方法 2.2 压力测试 1.将文件上传至云服务器 客户端上传:客户端将数据提交给云服务器,并等待其响应;用户…...
Linux: module: kheaders;CONFIG_IKHEADERS
文章目录 参考错误开一个玩笑。configcommit参考 https://github.com/iovisor/bcc/pull/2312 https://github.com/iovisor/bcc/pull/3588 https://bugs.gentoo.org/809347 https://lore.kernel.org/lkml/20190408212855.233198-1-joel@joelfernandes.org/ 错误 <built-in…...
Page 251~254 Win32 GUI项目
win32_gui 源代码: #if defined(UNICODE) && !defined(_UNICODE)#define _UNICODE #elif defined(_UNICODE) && !defined(UNICODE)#define UNICODE #endif#include <tchar.h> #include <windows.h>/* Declare Windows procedure */…...
Kafka(七)可靠性
目录 1 可靠的数据传递1.1 Kafka的可靠性保证1.2 复制1.3 Broker配置1.3.1 复制系数1.3.2 broker的位置分布1.3.3 不彻底的首领选举1.3.4 最少同步副本1.3.5 保持副本同步1.3.6 持久化到磁盘flush.messages9223372036854775807flush.ms9223372036854775807 1.2 在可靠的系统中使…...
Spring Data JPA入门到放弃
参考文档:SpringData JPA:一文带你搞懂 - 知乎 (zhihu.com) 一、 前言 1.1 概述 Java持久化技术是Java开发中的重要组成部分,它主要用于将对象数据持久化到数据库中,以及从数据库中查询和恢复对象数据。在Java持久化技术领域&a…...
MES系统数据采集的几种方式
生产制造执行MES系统具有能够帮助企业实现生产数据收集与分析、生产计划管理、生产过程监控等的功能板块,在这里小编就不一一介绍了,主要讲讲它的数据采集功能板块,可以说,数据采集是该系统进行数据统计与生产管理等后续工作的基础…...
铭文 LaunchPad 平台 Solmash 推出早鸟激励计划
为感谢用户对Solmash的支持,Solmash 特别推出“Solmash早鸟激励计划”,以回馈社区的早期参与者,这是专为已经参与Staking Pool或Honest Pool的用户推出的激励。 Solmash NFT激励 被列入早鸟计划的用户,可通过点击:sol…...
【前端规范】
1 前言 HTML 作为描述网页结构的超文本标记语言,一直有着广泛的应用。本文档的目标是使 HTML 代码风格保持一致,容易被理解和被维护。 2 代码风格 2.1 缩进与换行 [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符…...
12、JVM高频面试题
1、JVM的主要组成部分有哪些 JVM主要分为下面几部分 类加载器:负责将字节码文件加载到内存中 运行时数据区:用于保存java程序运行过程中需要用到的数据和相关信息 执行引擎:字节码文件并不能直接交给底层操作系统去执行,因此需要…...
【Docker】Docker安装入门教程及基本使用
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《Docker实战》。🎯🎯 &…...
语义解析:如何基于SQL去实现自然语言与机器智能连接的桥梁
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:"没有罗马,那就自己创造罗马~" 目录 语义解析 定义 作用 语义解析的应用场景 场景一: 场景二: 总结语…...
Java项目:117SpringBoot动漫论坛网站
博主主页:Java旅途 简介:分享计算机知识、学习路线、系统源码及教程 文末获取源码 117SpringBoot动漫论坛网站 一、项目介绍 动漫论坛网站是由SpringBootMybatis开发的,旅游网站分为前台和后台,前台为用户浏览,后台进…...
Jenkins基础篇--添加节点
节点介绍 Jenkins 拥有分布式构建(在 Jenkins 的配置中叫做节点),分布式构建能够让同一套代码在不同的环境(如:Windows 和 Linux 系统)中编译、测试等。 Jenkins 运行的主机在逻辑上是 master 节点,下图是主节点和从节点的关系。 添加节点 …...
【C++】手撕 list类(包含迭代器)
目录 1,list的介绍及使用 2,list_node 3,list_node() 3,list 4,list() 5,push_back(const T& x) 6,print() 7,_list_iterator 8,operator*() 9,…...
@Autowired 和 @Resource 的区别是什么?
Java面试题目录 Autowired 和 Resource 的区别是什么? Autowired 是 Spring 提供的注解。默认的注入方式为byType(根据类型进行匹配)。 Resource 是 JDK 提供的注解。默认注入方式为 byName(根据名称进行匹配)。 当一…...
栈和排序.
给你一个1->n的排列和一个栈,入栈顺序给定 你要在不打乱入栈顺序的情况下,对数组进行从大到小排序 当无法完全排序时,请输出字典序最大的出栈序列 输入 第一行一个数n 第二行n个数,表示入栈的顺序,用空格隔开&…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...
