归并排序递归法和非递归法的简单简单介绍

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

归并排序核心步骤:先将数组分组,往下分直到分为1个数据,然后开始合并,两两合并,合并的时候先比较两组数据中的数据的大小,按顺序依次合并到临时数组temp中,然后再将合并到temp数组中有序的数据覆盖到原数组中。

#include <stdio.h>
// 归并排序
// 时间复杂度O(N*logN)
// 空间复杂度O(N)
void _MergeSort(int* arr, int left, int right, int* temp)
{if (left >= right)return;// 递归划分区间,直到区间内只有一个数据后开始归并int mid = (left + right) / 2;// [left,mid] [mid+1,right]_MergeSort(arr, left, mid, temp);_MergeSort(arr, mid+1, right, temp);// 归并[left,mid] [mid+1,right]有序,归并到temp了int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int index = begin1;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2])temp[index++] = arr[begin1++];elsetemp[index++] = arr[begin2++];}// 可能有一段没结束,具体那一段不知道,只有一个循环可以进入while(begin1<=end1)temp[index++] = arr[begin1++];while (begin2 <= end2)temp[index++] = arr[begin2++];// 将归并后在temp的数据拷贝回原数组for (int i = left;i <= right; i++){arr[i] = temp[i];}
}// 归并排序
void MergeSort(int* arr, int n)
{assert(arr);int* temp = malloc(sizeof(int) * n);// 传入闭区间【0,n-1】_MergeSort(arr, 0, n - 1, temp);free(temp);
}void TestMergeSort()
{int arr[] = { 15,18,23,3,1,14,2,8,4,9,6,0,7 };MergeSort(arr, sizeof(arr) / sizeof(arr[0]));Printarry(arr, sizeof(arr) / sizeof(arr[0]));
}void TestMergeSortNonR()
{int arr[] = { 15,18,23,3,1,14,2,8,4,9,6,0,7 };MergeSortNonR(arr,sizeof(arr) / sizeof(arr[0]));Printarry(arr, sizeof(arr) / sizeof(arr[0]));
}int main()
{//TestInsertSort();//TestShellSort();//TestSelectSort();//TestBubbleSort();//TestHeapSort();//TestQuickSort();TestMergeSort();TestMergeSortNonR();return 0;
}

函数的递归实现图:

非递归法

从上面的递归图可以看出,合并的时候是2个数据开始合并,也就是区间【0,0】和【1,1】合并,【2,2】和【3,3】合并;然后【0,1】和【2,3】合并到这里时是两个数据两个数据之间合并,依次类推。那么非递归方法,需要控制好合并的下标即可。

// 归并排序--非递归方法
void MergeArry(int* arr, int begin1, int end1, int begin2, int end2, int* temp)
{int left = begin1, right = end2;int index = begin1;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2])temp[index++] = arr[begin1++];elsetemp[index++] = arr[begin2++];}// 可能有一段没结束,具体那一段不知道while (begin1 <= end1)temp[index++] = arr[begin1++];while (begin2 <= end2)temp[index++] = arr[begin2++];// 将归并后在temp的数据拷贝回原数组for (int i = left;i <= right; i++){arr[i] = temp[i];}
}void MergeSortNonR(int* arr, int n)
{assert(arr);int* temp = malloc(sizeof(int) * n);int gap = 1;  // 控制几个数据的合并排序while (gap < n){for (int i = 0;i < n;i += 2 * gap){// 归并+排序的区间(数组长度不是2的次方数时第二组可能会越界访问)// [i,i+gap-1] [i+gap,i+2*gap-1]int begin1 = i, end1 = i + gap - 1;    // 第一组int begin2 = i + gap, end2 = i + 2 * gap - 1;  // 第二组// 1、合并时只有第一组if (begin2 >= n)break;// 2、合并时第二组只有部分数据,需要修正边界if (end2 >= n)end2 = n - 1; // 只有一个数值的时候,直接让end2=最后一个数值就行了MergeArry(arr, begin1, end1, begin2, end2, temp);}Printarry(arr, n);gap *= 2;}free(temp);
}

实现图:

结论:

归并排序是一种基于分治思想的有效排序算法,其核心是通过递归将数组不断二分直至单个元素,然后按顺序合并有序子序列。算法分为递归和非递归两种实现方式:递归法通过_MergeSort函数划分区间并调用自身,然后将有序子序列合并到临时数组后回写;非递归法使用MergeSortNonR函数,通过gap变量控制合并步长,逐步扩大有序区间。两种方法都使用MergeArry函数进行具体合并操作,时间复杂度均为O(N*logN),空间复杂度为O(N)。代码示例展示了完整的实现过程,包括边界处理和数据拷贝等关键步骤。

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

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

相关文章

webrtc之子带分割下——SplittingFilter源码分析

文章目录前言一、频带分割过程1.SplittingFilter的创建2.频带分割整体流程1&#xff09;分割时机2&#xff09;分割规则3&#xff09;分割核心代码3.频带合并二、算法实现1.实现原理介绍2.All pass QMF系统源码1&#xff09;提高精度2&#xff09;经过串联全通滤波器3&#xff…

Java运维之Tomcat升级

Tomcat升级准备工作 下述所有过程中,包含了两种升级方式,一种是备份旧版本的 bin 和 lib,将新版本的 bin 和 lib 对旧版本进行覆盖;另一种是直接备份旧版本的Tomcat包,运行新版本,将旧版本的配置文件(conf/ * )和应用(webapps/ * )等同步到新版本。 1. 到官网下载指…

MySQL的可重复读隔离级别实现原理分析

MySQL 的 可重复读&#xff08;Repeatable Read, RR&#xff09; 隔离级别主要通过 多版本并发控制&#xff08;Multi-Version Concurrency Control, MVCC&#xff09; 和 锁机制&#xff08;特别是间隙锁&#xff09; 来实现的。其核心目标是&#xff1a;在一个事务内&#xf…

利用Java自定义格式,循环导出数据、图片到excel

利用Java自定义格式&#xff0c;循环导出数据、图片到excel1、自定义格式循环导出数据1.1.设置格式1.1.1、居中样式1.1.2、应用样式到合并区域1.1.3、合并单元格1.1.4、设置列宽1.2、写入数据1.2.1、创建标签头部1.2.2、写入标签内容2、自定义格式循环导出图片2.1、设置格式并插…

SAP学习笔记 - 开发45 - RAP开发 Managed App New Service Definition,Metadata Extension

上一章讲了在 Data Model View ( CDS View for BO Structure )基础上创建 Projection View ( CDS View for BO Projection )。 SAP学习笔记 - 开发44 - RAP开发 Managed App 建 Projection View&#xff0c;Provider Contract&#xff0c;用 redirected to 设定父子关系-CSDN博…

React强大且灵活hooks库——ahooks入门实践之高级类hook(advanced)详解

什么是 ahooks&#xff1f; ahooks 是一个 React Hooks 库&#xff0c;提供了大量实用的自定义 hooks&#xff0c;帮助开发者更高效地构建 React 应用。其中高级类 hooks 是 ahooks 的一个重要分类&#xff0c;专门用于处理一些高级场景&#xff0c;如受控值、事件发射器、性能…

计算机网络——数据链路层(25王道最新版)

数据链路层前言数据链路层的功能封装成帧&#xff08;组帧&#xff09;字符计数法字节填充法零比特填充法违规编码法小节差错控制检错编码奇偶校验码CRC校验码&#xff08;循环冗余校验码&#xff09;基本思想如何构造如何检错纠错纠错编码海明校验码设计思路求解步骤&#xff…

【PTA数据结构 | C语言版】字符串替换算法

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 请编写程序&#xff0c;将给定主串 s 中的子串 sub_s 替换成另一个给定字符串 t&#xff0c;再输出替换后的主串 s。 输入格式&#xff1a; 输入给出 3 个非空字符串&#xff0c;依次为&#xff1a…

事物生效,订单类内部更新订单

代码如下以下代码1不生效&#xff0c;2生效解决方案1&#xff0c;外层方法加注解&#xff0c;内层不加2&#xff0c;不要拆分方法&#xff0c;把更新订单操作放在带事物的大方法中3&#xff0c;拆方法&#xff08;内部&#xff09;&#xff0c;注入自己&#xff0c;用代理对象调…

非对称加密:RSA

文章目录 非对称加密:RSA 1、RSA 加解密 2、RSA 生成密钥对(公钥、私钥)、加解密 参考资料 非对称加密:RSA 1、RSA 加解密 <!-- RSA --><!-- 引入jsencrypt库 --><script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js&q…

MongoDB 数据库 启用访问控制

0. 最近服务器安装了 MongoDB 被勒索了 测试服务器安装了 MongoDB 等&#xff0c;开放了 27017 对所有 ip。 哈哈哈哈哈哈&#xff0c;问就是有点犯懒&#xff0c;之前都是只允许自己的 ip。 好家伙&#xff0c;然后没过几个小时&#xff0c;数据库集合被清空&#xff0c;只留…

【Unity Sprite属性拓展】

Unity Inspector 精灵图预览为 Unity 中的 Sprite 类型属性提供了​​增强版的 Inspector 显示​​&#xff0c;在保留标准精灵选择功能的基础上&#xff0c;添加了大型预览图和精灵名称显示功能代码 using UnityEngine; using UnityEditor;// 1️⃣ 告诉 Unity&#xff1a;所有…

细菌实验入门:浓度测定与菌种鉴定技术详解

在微生物实验中&#xff0c;细菌浓度的精准测定和菌种的准确鉴定是两项基础且核心的操作。本文将详细介绍相关技术的原理、操作步骤及注意事项&#xff0c;为新手提供系统性指导。一、细菌浓度测定方法1. 光密度法&#xff08;OD600&#xff09;&#xff1a;快速定量的首选原理…

GaussDB 数据库架构师修炼(一)数据库容量规划

1、容量规划的定义GaussDB容量规划是指根据客户业务系统的负载需求或历史运行数据&#xff0c;进行合理规划GaussDB的计算、存储和网络资源配置&#xff0c;以满足业务系统正常使用和未来若干年负载增长诉求的过程。2、容量规划活动主要步骤需求收集调研生产系统的业务特征&…

hashMap原理(一)

概念HashMap是java中一种非常常用的基于哈希表的数据结构&#xff0c;允许o(1)的时间复杂度进行元素插入&#xff0c;查找&#xff0c;和删除。它通过”键-值“ 对的方式存储数据。总的来说&#xff1a;HashMap的底层原理&#xff1a;数组链表红黑树&#xff08;jdk1.8之后还涉…

Ubuntu24 辅助系统-屏幕键盘的back按键在网页文本框删除不正常的问题解决方法

Ubuntu24 辅助系统-屏幕键盘的back按键异常 问题描述ubuntu24这个屏幕键盘&#xff0c;只有在网页的搜索框或者文本框&#xff0c;比如百度首页的搜索框&#xff0c;留言的文本框&#xff0c;才会出现点击back按钮的时候&#xff0c;出现了先选中当前这个字符&#xff0c;删除此…

自然语言指令驱动的工业机器人协同学习系统:大语言模型如何重塑智能体协作范式

重磅推荐专栏: 《大模型AIGC》 《课程大纲》 《知识星球》 本专栏致力于探索和讨论当今最前沿的技术趋势和应用领域,包括但不限于ChatGPT和Stable Diffusion等。我们将深入研究大型模型的开发和应用,以及与之相关的人工智能生成内容(AIGC)技术。通过深入的技术解析和实践经…

web:js的switch语句

在js中,switch语句是一种用于根据不同的条件执行不同代码块的控制流语句。它类似于多个if...else if...else语句,但结构更清晰,特别是在有多个条件分支的情况下。 基本语法 switch (expression) {case value1:// 当expression的值等于value1时执行这里的代码break;case va…

为何说分布式 AI 推理已成为下一代计算方式

2024 年&#xff0c;我们见证了人工智能创新的空前爆发。AI 的快速发展令很多人惊叹&#xff0c;为了训练更先进的大语言模型&#xff08;LLM&#xff09;&#xff0c;科技巨头争相获取强大的 GPU。如今&#xff0c;AI 正在无缝融入我们世界的每个角落。在众多新兴 AI 公司、模…

阿里云 RabbitMQ 可观测性最佳实践

阿里云 RabbitMQ 阿里云 RabbitMQ 是一款高性能、高可靠的消息中间件&#xff0c;支持多种消息协议和丰富的功能特性。它提供消息队列功能&#xff0c;能够实现应用间的消息解耦和异步通信&#xff0c;提升系统扩展性和稳定性。其支持多种消息持久化策略&#xff0c;确保消息不…