c语言-归并排序

       

目录

1、归并排序基本思想

2、归并排序的实现(递归法)

2.1 代码实现递归法归并排序 

3、归并排序的实现(非递归法)

3.1 修正边界问题

 3.2 代码实现非递归法归并排序 

结语: 


前言:

        归并排序是一种把数组排成有序数组的分治算法,其逻辑和归并操作是一样的,就是把两个子序列合并成一个子序列,只不过归并排序是把两个有序的子序列合并成一个有序的子序列,最后完成对数组的排序。

1、归并排序基本思想

        归并排序就是把一个数组看成是由两个子序列构成,这两个子序列再继续细分,是由四个子序列构成,四个子序列又分成由八个子序列构成...如此细分下去直到一个元素代表一个序列。这样就能够将两个子序列合并成一个序列,因为此时一个序列代表一个元素,可以直接进行元素的比较,从而构成一个新的含两个元素的有序序列。

2、归并排序的实现(递归法)

         首先把数组分成两个左右区间(既序列),然后这两个左右区间再进行分区间。

        总逻辑图:

        可以从上图中看到,对一个数组不断进行分解,直到分解至最后一个元素就进行归并,该结构类似二叉树的递归结构,从递归的思想出发,也就是当递归到最后一个元素的时候,则无需再递归,递归函数逐渐向上”回收“,并且完成排序。       


        但是如果在原数组内进行分解和归并等操作则过于复杂,因此动态开辟一个新的数组temp,让相邻元素组进行归并的时候都在数组temp上完成,最后再把新数组temp上的数据用memcpy拷贝到原数组上覆盖原先的元素的顺序,达到对原数组排序的效果。


        然后把数组temp中元素拷贝到原数组内,这样原数组的元素顺序就得到了改变。 


        当然以上只是一部分的操作,整体逻辑与上相同,并且重复以上操作。

        最后一步就是对1 5 6 10和2 3 4 9这两组进行归并,得到的序列就是最终的有序序列。


        不过在此要还要注意拷贝到temp数组时,要拷贝到对应的位置上。

2.1 代码实现递归法归并排序 

        代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>void _MergeSort(int* a, int left, int right, int* temp)//归并排序
{if (left == right)//left==right说明递归至只有一个元素,开始向上“收回”return;int mid = (left + right) / 2;//按照mid让数组分成两个区间//递归函数_MergeSort(a, left, mid, temp);_MergeSort(a, mid + 1, right, temp);//begin1表示要进行归并的第一组元素的第一个元素,end1表示该组元素的最后一个元素//begin2表示要进行归并的第二组元素的第一个元素,end2表示该组元素的最后一个元素//begin1、end1和begin2、end2的作用就是让元素组两两进行归并int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int i = left;//i的值temp数组的下标while (begin1 <= end1 && begin2 <= end2)//归并操作{if (a[begin1] > a[begin2])//小的元素先放到temp数组中temp[i++] = a[begin2++];else//其他情况则放在后面temp[i++] = a[begin1++];}//走到这里表示有一个元素组为空,则直接把另一个元素组移到temp数组中即可while (begin1 <= end1){temp[i++] = a[begin1++];}while (begin2 <= end2){temp[i++] = a[begin2++];}//最后从temp数组中拷贝至原数组中要严格按照位置拷贝,left表示当前归并的位置memcpy(a + left, temp + left, sizeof(int) * (right - left + 1));
}
void MergeSort(int* a, int n)//归并排序
{int* temp = (int*)malloc(sizeof(int) * (n + 1));//开辟新数组if (temp == NULL){perror("malloc");return;}_MergeSort(a, 0, n, temp);free(temp);
}void PrintArr(int* a, int n)//打印数组
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}void Test_MergeSort()//归并排序
{int arr[] = { 10,5,6,1,2,4,3,9 };int sz = sizeof(arr) / sizeof(int);PrintArr(arr, sz);MergeSort(arr, sz - 1);PrintArr(arr, sz);
}int main()
{Test_MergeSort();return 0;
}

        运行结果:

        从结果看出递归法可以完成归并排序。 

3、归并排序的实现(非递归法)

        非递归方法思路图如下:

        从上图可以看出,非递归法与递归法的区别:只不过是把层层递归至只剩一个元素一组的思想换成了一开始就从一个元素一组往后不断增加每组的元素个数。其中,要进行归并的元素组1的第一个元素依然是begin1,最后一个元素是end1。元素组2的第一个元素依然是begin2,end2。

        但是非递归法再面对数组有九个元素的时候,就不能像以上一样每组元素完整的对比了。

3.1 修正边界问题

        不过非递归法再处理数组元素个数不为2的幂次方时,比如对要排序的数组的元素个数为9个时,会出现越界问题。

        这里begin2和end2的值明显是超出了数组的最后一个元素的下标值,因此如果访问begin2、end2会发生越界。所以这里采取让begin2的值大于end2的值,让他们成为一个不存在的区间,因此在代码中就不会对他们进行访问了(结合上述代码中归并操作while循环条件)。


        从上文的非递归思路图来看,当数组中有8个元素,则在gap=4的时候就完成了对数组的排序,也可以理解为当gap=8时结束排序操作。但是若数组中有9个元素,则gap=8时并不会结束排序操作,而是会再进行一轮排序,而该轮排序就是对第9个元素进行归并的关键一轮排序,所以在gap=8之前我们要让第9个元素和与他对比的元素组不参与进来,等到gap=8时,在进行对end2的修正从而间接的让第9个元素进行归并。

 3.2 代码实现非递归法归并排序 

        代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
#include<stdlib.h>
#include<string.h>void _MergeSortNon(int* a, int n, int* temp)//归并排序(非递归法)
{int gap = 1;//从一个元素一个元素组开始while (gap < n)//gap>=n时说明排序完成{int j = 0;//temp数组下标for (int i = 0; i < n; i += 2 * gap)//元素组1和下一个元素组1直接的间隔是2*gap{//设置元素组1和元素组2的第一个元素和最后一个元素下标int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//修正if (end1 >= n)//当end1超出范围则表示begin2和end2也超出范围{end1 = n - 1;//修正end1让其等于begin1,表示该元素在数组中没有变动//让元素组2的begin2>end2,目的不让其进入下面的while循环,也就不会发生越界了begin2 = n;end2 = n - 1;}else if (begin2 >= n)//目的也是不然元素组2进入while循环{begin2 = n;end2 = n - 1;}else if (end2 >= n)//来到这局代码,说明begin2<n,这时修正end2让其等于begin2{end2 = n - 1;}//归并操作,和上文逻辑一样while (begin1 <= end1 && begin2 <= end2){if (a[begin1] > a[begin2])temp[j++] = a[begin2++];elsetemp[j++] = a[begin1++];}while (begin1 <= end1){temp[j++] = a[begin1++];}while (begin2 <= end2){temp[j++] = a[begin2++];}}memcpy(a, temp, sizeof(int) * n);//最后拷贝数组即可gap *= 2;}
}
void MergeSortNon(int* a, int n)//归并排序(非递归法)
{int* temp = (int*)malloc(sizeof(int) * n);if (temp == NULL){perror("malloc");return;}_MergeSortNon(a, n, temp);free(temp);
}void PrintArr(int* a, int n)//打印数组
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}void Test_MergeSortNon()//归并排序(非递归法)
{int arr[] = { 10,5,6,1,2,4,3,9,0, };int sz = sizeof(arr) / sizeof(int);PrintArr(arr, sz);MergeSortNon(arr, sz);PrintArr(arr, sz);
}int main()
{Test_MergeSortNon();return 0;
}

        运行结果:

        从结果中可以看出非递归法也能实现归并排序。

结语: 

         以上就是关于归并排序的介绍,归并排序的递归法和非递归法主要还是以归并操作的逻辑为主。只是对于归并排序的非递归方法而言,其逻辑确实有些复杂,但是只要理解了边界修正的问题还是能够很好的理解此方法的,最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充~!!谢谢大家!!(~ ̄▽ ̄)~

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

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

相关文章

Python---格式化输出与%百分号----涉及转义符 \ 反斜杠的使用

相关链接Python--格式化输出中的转义符号----\t 制表符&#xff08;空格的&#xff09;和\n&#xff08;换行的&#xff09;_唯元素的博客-CSDN博客 Python---字符串&#xff08;用单、双引号、 三单/双引号定义。反斜杠 \ 转义&#xff0c;单在双内/双在单内 &#xff09;-CS…

力扣 --- 最后一个单词的长度

题目描述&#xff1a; 给你一个字符串 s&#xff0c;由若干单词组成&#xff0c;单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello World&…

运维02:Linux

Linux安装 VMWare安装&#xff1a;夸克网盘分享&#xff08;提取码&#xff1a;refg&#xff09; CentOS安装&#xff1a;Index of /centos/7.9.2009/isos/x86_64/ Xshell安装&#xff1a;百度网盘 请输入提取码&#xff08;提取码&#xff1a;juau&#xff09; 环境准备 1、…

在Windows 11中,把iPhone照片和视频导出来又快又简单,无需第三方软件

如果你想将照片和视频从iPhone传输到Windows 11 PC&#xff0c;最快、最简单的方法是插入手机并执行自动导入。以下是操作方法。 如何将照片和视频从iPhone导入Windows 如果你用USB数据线将iPhone插入Windows PC&#xff0c;Windows 11可以像标准数码相机一样连接到它&#x…

react之封装有无Token(路由权限控制)的高阶组件

TOC 前景 有些路由页面内的内容信息比较敏感&#xff0c;如果用户没有经过登录获取到有效Token&#xff0c;是没有权限跳转的&#xff0c;根据Token的有 无控制当前路由是否可以跳转就是路由的权限控制 技术方案 实现步骤 1.在 components 目录中&#xff0c;创建 AuthRoute/in…

solidity实现ERC721代币标准发布NFT

文章目录 1、非同质化货币&#xff08;NFT&#xff09;- 维基百科2、IERC1653、IERC7214、IERC721Receiver5、IERC721Metadata6、ERC7217、ERC721 NFT 的实现8、编译部署 1、非同质化货币&#xff08;NFT&#xff09;- 维基百科 非同质化代币&#xff08;英语&#xff1a;Non-F…

Elasticsearch:什么是大语言模型(LLM)?

大语言模型定义 大语言模型 (LLM) 是一种深度学习算法&#xff0c;可以执行各种自然语言处理 (natural language processing - NLP) 任务。 大型语言模型使用 Transformer 模型&#xff0c;并使用大量数据集进行训练 —— 因此规模很大。 这使他们能够识别、翻译、预测或生成文…

时间复杂度为O (nlogn)的排序算法

归并排序 归并排序遵循分治的思想&#xff1a;将原问题分解为几个规模较小但类似于原问题的子问题&#xff0c;递归地求解这些子问题&#xff0c;然后合并这些子问题的解来建立原问题的解&#xff0c;归并排序的步骤如下&#xff1a; 划分&#xff1a;分解待排序的 n 个元素的…

【c】求一组数据的最大值和第二大的值

我们可以创建数组&#xff0c;利用冒泡排序法把数组进行排序&#xff0c;但是当元素过多时候循环可能过多导致循环超限 所以我们可以换种其他方法&#xff0c;代码附上 #include<stdio.h> int main() {int n,i;puts("输入这组数据的个数");scanf("%d&qu…

进行主从复制时出现的异常FATAL CONFIG FILE ERROR (Redis 6.2.6)Reading the configuration file

错误如下所示&#xff1a; FATAL CONFIG FILE ERROR (Redis 6.2.6) Reading the configuration file, at line 1 >>> include/myredis/redis.conf Bad directive or wrong number of arguments出现错误的原因是.conf文件中命令之间缺少空格&#xff0c;如下所示&…

QML中常见布局方法

目录 引言常见方法锚定&#xff08;anchors&#xff09;定位器Row、ColumnGridFlow 布局管理器RowLayout、ColumnLayoutGridLayoutStackLayout 总结 引言 UI界面由诸多元素构成&#xff0c;如Label、Button、Input等等&#xff0c;各种元素需要按照一定规律进行排布才能提高界…

Prime 2.0

信息收集 # Nmap 7.94 scan initiated Thu Nov 23 20:09:06 2023 as: nmap -sn -oN live.nmap 192.168.182.0/24 Nmap scan report for 192.168.182.1 Host is up (0.00018s latency). MAC Address: 00:50:56:C0:00:08 (VMware) Nmap scan report for 192.168.182.2 Host is u…

长度最小的子数组(Java详解)

目录 题目描述 题解 思路分析 暴力枚举代码 滑动窗口代码 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条…

OpenCvSharp从入门到实践-(06)创建图像

目录 1、创建图像 1.1实例1-创建黑色图像 1.2实例2-创建白色图像 1.3实例3-创建随机像素的雪花点图像 2、图像拼接 2.1水平拼接图像 2.2垂直拼接图像 2.3实例4-垂直和水平两种方式拼接两张图像 在OpenCV中&#xff0c;黑白图像其实就是一个二维数组&#xff0c;彩色图像…

[ Linux Audio 篇 ] 音频开发入门基础知识

在短视频兴起的背景下&#xff0c;音视频开发越来越受到重视。接下来将为大家介绍音频开发者入门知识&#xff0c;帮助读者快速了解这个领域。 轻柔的音乐、程序员有节奏感的键盘声、嗡嗡的发动机、刺耳的手提钻……这些声音是如何产生的呢&#xff1f;又是如何传到我们耳中的…

SpringSecurity和JWT实现认证和授权

SpringSecurity和JWT实现认证和授权 框架介绍SpringSecurityJWT组成实例JWT实现认证和授权的原理 Hutool 使用表整合SpringSecurity及JWT在pom.xml中添加依赖添加JWT token的工具类添加RbacAdminService&#xff1a;添加自定义mapper创建SpringSecurity配置类添加ProjectSecuri…

Redis--14--BigKey 和 热点Key

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 BigKey1.什么是bigkey2.bigkey的危害3.发现bigkeyscan 4.解决bigkey 什么是热点Key&#xff1f;该如何解决1. 产生原因和危害原因危害 2.发现热点key预估发现客户端…

Stable Diffusion AI绘画系列【11】:超萌的Q版手办萌宠系列

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

送女朋友一个猜数字小游戏,猜对了会显示爱心(给你心爱的他或她一个惊喜)

起因是我在学习C语言完成老师布置C语言写一个猜数字的作业&#xff0c;突发奇想&#xff0c;能不能在这个猜对了之后弹出一个不一样的页面&#xff0c;然后就试试看能不能实现。基本思路是这样的&#xff1a; 1&#xff1a;先写一个C语言的猜数字的小游戏&#xff0c;在我上个文…

StackGres 1.6 数据库平台工程功能介绍以及快速上手

StackGres 1.6 数据库平台工程功能 声明式 K8S CRs StackGres operator 完全由 Kubernetes 自定义资源管理。除了 kubectl 或任何其他 Kubernetes API 访问之外&#xff0c;不需要安装任何客户端或其他工具来管理 StackGres。您的请求由 CRD 的 spec 部分表示&#xff0c;任何 …