【排序算法】—— 归并排序

        归并排序时间复杂度O(NlongN),空间复杂度O(N),是一种稳定的排序,其次可以用来做外排序算法,即对磁盘(文件)上的数据进行排序。

目录

一、有序数组排序

二、排序思路

三、递归实现

四、非递归实现


一、有序数组排序

要理解归并排序的核心逻辑我们得先看懂下面一个题:

         刚接触这个题的时候,大家可能会想把他俩写到一个数组里面然后再写一个排序算法,这是一个比较容易想到也是比较蛮力的一种方法,但是这里有一个特点这两个数组是有序的。所以有一个很巧妙的方法。

        使用两个变量分别记录他们的下标,并从零下标开始,比较他们下标对应下的值把小的那个先放进去新数组里面,然后把他的下标移到下一位。然后重复进行该操作,直到把其中的一个遍历完。
        当然此时还没有完全排完序,当其中一组遍历完后,还有另一组剩余的的元素没有放在新数组内,因为无法确定那一组会先遍历完所以我们俩组都需要检查一遍,检查他们的下标并把剩余元素放在新数组内

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int main()
{int ar1[] = { 1,2,3,4 };int ar2[] = { 3,4,5,6,7 };int sz1 = sizeof(ar1)/sizeof(int), sz2 = sizeof(ar2) / sizeof(int);int* arr = (int*)malloc(sizeof(int) * (sz1 + sz2));assert(arr);int i = 0, j = 0, t = 0;while (i < sz1 && j < sz2){if (ar1[i] < ar2[j])arr[t++] = ar1[i++];elsearr[t++] = ar2[j++];}while (i < sz1)arr[t++] = ar1[i++];while (j < sz2)arr[t++] = ar2[j++];for (int i = 0; i < sz1 + sz2; i++)printf("%d ", arr[i]);return 0;
}

二、排序思路

        通过理解上面那个题,那么对于一个乱序的数组,我们可以把一分为二,先让两个小数组有序然后再用上面的方法合并。那么如何让这两个小数组有序呢,同样的可以把他们分别再拆开,变成四个小组,然后继续一直往下拆,直到拆到只有一个元素,那么它必然是有序的,最后进行进行一一合并,这整个的思路有点像二叉树的后续遍历

动图:

三、递归实现

        在分析的过程中,我们就可以感受到使用递归可以很好的解决这个问题。在做分割的时候,最好是选择从中间位置开始,这样避免的递归深度太深。在处理递归问题的时候还要注意一个点,就是递归的结束条件,这里递归什么时候结束呢?通过上面的分析当数组只分割成单个元素的时候它必然是有序的,那么递归结束条件就是当分割的小数组只有一个元素的时候返回。

代码示例:

void _MergeSort(int* arr, int* tmp, int left, int right)
{if (left >= right)return;int key = (left + right) / 2;int begin1 = left, end1 = key;int begin2 = key + 1, end2 = right;_MergeSort(arr, tmp, begin1, end1);_MergeSort(arr, tmp, begin2, end2);int i = left;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2])tmp[i++] = arr[begin1++];elsetmp[i++] = arr[begin2++];}while (begin1 <= end1)tmp[i++] = arr[begin1++];while (begin2 <= end2)tmp[i++] = arr[begin2++];memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
}
void MergeSort(int* arr, int size)//归并排序——递归
{int* tmp = (int*)malloc(sizeof(int) * size);assert(tmp);_MergeSort(arr, tmp, 0, size - 1);free(tmp);
}

四、非递归实现

        把递归转为非递归可以防止函数栈针开的太多导致栈溢出。在把递归转为非递归时第一想到的应该是使用栈结构来辅助完成。但是对于这个排序使用栈来实现非递归还是比较复杂,也根本用不着。

思路:

        gap:表示分割的每个小数组中储存的元素个数。

        size:表示整个大数的长度

        首先我们仿照广度优先的思想去合并,因为刚开始只有单个元素自己作为一个数组(即gap=1)的时候才有序,所以从最后一层开始两两合并成一个,那么接下来gap=2的小数组就变得有序,合并完gap=2的的数组后,同理gap=4的小数组变得有序,对它们进行两两合并,直到gap>=size

代码示例: 

void MergeSortNoF(int* arr, int sz)
{int* tmp = (int*)malloc(sizeof(int) * sz);assert(tmp);int gap = 1;while (gap < sz){for (int i = 0; i < sz; i += gap * 2){int j = i;int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;if (begin2 >= sz)break;if (end2 >= sz)end2 = sz - 1;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] <= arr[begin2])tmp[j++] = arr[begin1++];elsetmp[j++] = arr[begin2++];}while (begin1 <= end1)tmp[j++] = arr[begin1++];while (begin2 <= end2)tmp[j++] = arr[begin2++];memmove(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));}gap*=2;}
}

细节:

        无论是递归还是非递归都需要开辟一块空间tmp来储存合并后的元素,最后把tmp上的数据拷贝给原数组,使用memmove函数比较便捷。

区间越界问题:

        (1)、[begin1, end1]    [begin2, end2

        (2)、[begin1, end1]    [begin2, end2

        (3)、[begin1, end1]    [begin2, end2

        以上红色表示越界,这是越界可能出现的所有情况,观察发现出现(2),(3)种情况的时候并不需要做合并,直接break;怎么写条件呢?因为end1越界begin2一定越界,所有用一个if(begin2>=sz)就可以表示(2),(3)种情况。

        至于第一种情况,我们还是要合并的但需要调整end2为sz-1,所以有一下代码:

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

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

相关文章

mysql(5.5)启动服务和环境配置

正常启动 参考&#xff1a;Javaweb基础之mysql回溯笔记(一) 总的来说就是在mysql的安装目录下&#xff0c;找到bin下面的msyqld.exe&#xff0c;双击即启动了mysql服务&#xff1b; 启动方式二 也可以直接找到windows的服务项进行启动&#xff0c;操作如下&#xff1a; 打开…

Mac电脑下运行java命令行出现:错误: 找不到或无法加载主类

mac 电脑 问题复现 随手写了一个main方法&#xff0c;想用命令行操作 进入 BlockDemo.java 所在目录&#xff1a; wnwangnandeMBP wn % cd /Users/wn/IdeaProjects/test/JianZhiOffer/src/main/java/com/io/wn wnwangnandeMBP wn % ls -l total 16 -rw-r--r-- 1 wangnan …

换手机了怎么恢复微信聊天记录?教你3招实用技巧

随着科技的飞速发展&#xff0c;手机更新换代的速度也越来越快。当我们换上一部新手机时&#xff0c;最头疼的问题之一往往是如何将旧手机中的重要数据&#xff0c;尤其是微信聊天记录&#xff0c;迁移到新手机上。微信聊天记录不仅记录了我们的日常沟通&#xff0c;还承载了许…

踩坑日记 | 记一次流程图问题排查

踩坑日记&#xff1a;记一次流程图问题排查 标签&#xff1a; activiti | 流程 引言 今天排查了一个流程图问题&#xff0c;耗时2个小时终于解决&#xff0c;记录下来 现象 流程审批驳回报错&#xff1a;Unknown property used in expression: ${xxxx} 使用的是 activiti …

[C/C++入门][循环]12、等差数列和等差数列末项计算

等差数列是什么&#xff1f; 想象一下&#xff0c;你获得了一个神奇的糖果盒&#xff0c;他有一个神奇的功能&#xff0c;每次你打开盒子时&#xff0c;里面都会多出同样数量的糖。你只要给里面放上1颗糖&#xff0c;然后想着可以多几颗&#xff0c;比如我希望打开的时候多两颗…

【C++练级之路】【Lv.26】类型转换

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 一、C风格类型转换1.1 隐式类型转换1.2 显式类型转换 二、C风格类型转换2.1 static_cast2.2 dynamic_cast2.3…

配置Redis时yml的格式导致报错

报错如下 java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98) at org.springframework.test.context.su…

Unity 优化合集

1️⃣ 贴图优化 1. Read/Write Enable 这个属性勾选后允许你在运行时读取和写入纹理数据&#xff0c;这对于需要实时生成内容或者需要动态修改纹理的场合非常有用但在大部分情况下这是不必要的。如果打开这个属性&#xff0c;会使运行时贴图大小翻倍&#xff0c;内存中会额外…

gptpdf:使用大模型(如 GPT-4o)将 PDF 解析为 markdown。

今天给大家分享一个开源的项目&#xff0c; 使用视觉大语言模型&#xff08;如 GPT-4o&#xff09;将 PDF 解析为 markdown。 方法非常简单(只有293行代码)&#xff0c;但几乎可以完美地解析排版、数学公式、表格、图片、图表等。 使用 GeneralAgent lib 与 OpenAI API 交互。…

香橙派AIpro部署YOLOv5:探索强悍开发板的高效目标检测能力

香橙派AIpro部署YOLOv5&#xff1a;探索强悍开发板的高效目标检测能力 一、香橙派AIpro开箱使用体验 1.1香橙派AIpro开箱 拿到板子后第一件事情就是开箱&#xff1a; 开箱后可以看见一个橘子的标识&#xff0c;也就是香橙派了&#xff0c;并且还有四个大字&#xff1a;为AI…

RABBITMQ的本地测试证书生成脚本

由于小程序要求必须访问wss的接口&#xff0c;因此需要将测试环境也切换到https&#xff0c;看了下官方的文档 RabbitMQ Web STOMP Plugin | RabbitMQ里面有这个信息 然后敲打GPT一阵子&#xff0c;把要求输入几个来回&#xff0c;得到这样一个脚本&#xff1a; generate_cer…

双向带头循环链表

一、概念 何为双向&#xff1a;此链表每一个节点的指针域由两部分组成&#xff0c;一个指针指向下一个节点&#xff0c;另一个指针指向上一个节点&#xff0c;并且两头的节点也是如此&#xff0c;头节点的下一个节点是尾节点&#xff0c;尾节点的上一个节点是头节点&#xff1b…

R语言实战——栅格聚合方法(超方便)

今天给大家分享一个栅格聚合方法&#xff0c;使用R语言实现&#xff01; 1 为什么要做栅格聚合 栅格数据是我们地理学使用最广泛的数据类型之一。所谓栅格聚合其实就是根据栅格数据进行一系列运算得到一个我们想要的数据。 我个人认为&#xff0c;应用最广泛的&#xff0c;可…

notepad++中文出现异体汉字,怎么改正

notepad显示异体字&#xff0c;如何恢复&#xff1f; 比如 “门” 和 “直接” 的"直"字&#xff0c;显示成了 方法 修改字体&#xff0c; 菜单栏选择 Settings(设置&#xff09;&#xff0c;Style Configurator…&#xff08;语言格式设置…&#xff09;&#xf…

SSM城镇居民社区再生资源回收系统-计算机毕业设计源码04175

摘 要 本论文介绍了一个基于SSM&#xff08;Spring Spring MVC MyBatis&#xff09;技术的城镇居民社区再生资源回收系统的设计与实现。随着社会对环境保护意识的不断提高&#xff0c;再生资源回收成为了一种重要的环保行动。然而&#xff0c;传统的再生资源回收方式存在着信…

[数仓]十二、离线数仓(Atlas元数据管理)

第1章 Atlas入门 1.1 Atlas概述 Apache Atlas为组织提供开放式元数据管理和治理功能,用以构建其数据资产目录,对这些资产进行分类和管理,并为数据分析师和数据治理团队,提供围绕这些数据资产的协作功能。 Atlas的具体功能如下: 元数据分类 支持对元数据进行分类管理,例…

springboot3——项目部署

springboot的项目开发完了&#xff0c;怎么样把他放到服务器上或者生产环境上让他运行起来跑起来。就要牵扯到项目部署&#xff0c;打包的方式了。 springboot支持jar和war: 打jar包&#xff1a;默认方式&#xff0c;项目开发完打个jar包&#xff0c;通过命令把jar包起起来就…

刚刚,Claude国内可直连!

刚刚&#xff0c;Claude国内可直连&#xff01; 大家好&#xff01;我是科技博主Maynor。今天我们要分享一个激动人心的消息&#xff1a;知名AI助手Claude现在可以在国内直接访问了&#xff01; 这对于科技爱好者、学生、研究人员和各行各业的专业人士来说都是一个重大利好。…

大模型时代的小红书+马蜂窝:华人团队开发 的AI旅行app

简介 一周前&#xff0c;由红杉投资的硅谷初创公司UTA AI推出了其核心产品Wanderboat AI&#xff0c;这是一个基于GPT-4技术的智能旅行规划工具。 该平台允许用户通过对话交互来明确旅行的偏好和需求&#xff0c;并提供包括目的地、活动和实用建议在内的定制化旅行建议。 Wa…

算法题-字符串

1.C字符串 c提供了一下两种类型的字符串表示形式&#xff1a; c风格字符串c引入的string类类型 1.1C风格字符串 C 风格的字符串起源于 C 语言&#xff0c;并在 C 中继续得到支持。字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此&#xff0c;一个以 null 结尾的…