当前位置: 首页 > news >正文

【数据结构】归并排序 的递归实现与非递归实现

归并排序

  • 前言
  • 一、归并排序递归实现
    • (1)归并排序的核心思路
    • (2)归并排序实现的核心步骤
    • (3)归并排序码源详解
    • (4)归并排序效率分析
      • 1)时间复杂度 O(N*logN)
      • 2)空间复杂度 O(N)
      • 稳定性:稳定
  • 二、归并排序的非递归实现
    • (1) 关于递归的缺点的讨论
  • (2) 归并排序 非递归算法实现思路
  • (3)码源详解
  • (4)运行结果



前言

快速排序:前序
归并排序:后序



一、归并排序递归实现

(1)归并排序的核心思路

将 已有序的子序列 合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。


(2)归并排序实现的核心步骤

在这里插入图片描述

  1. 向下递归 对半分割
  2. 递归返回条件:递归到最小,1个即是有序 [ 控制的是范围 归并的区间 ]
  3. 递归到最深处,最小时,就递归回去,开始分按对半分割分出的范围, 将 已有序的子序列 合并,在 tmp 里进行归并。
  4. 将tmp里形成的有序序列,拷贝回原数组 【 因为下一次递归回去上一层再进行下一次的归并过程中,会将数据在tmp中进行归并,会将tmp中的数据覆盖,所以要及时将小部分已归并排好序的子序列拷贝回原数组 】
  5. 再进行递归返回上一层的递归归并,直到递归层数都结束。


(3)归并排序码源详解

void _MergeSort(DataType* a, DataType* tmp, int begin, int end) {if (begin>=end) {      //递归返回的条件:不正常的的范围 或 只剩1个数return;}int mid = (begin + end) / 2;//先递归到最小//[begin,mid][mid+1,end]_MergeSort(a, tmp, begin, mid);    //数组是从0开始,所以end=mid-1这样设计_MergeSort(a, tmp, mid+1, end);//再进行归并 —— 所以归并的过程,设计在递归后面(后序)//归并到tmp数组,再拷贝回去int begin1 = begin; int end1 = mid;int begin2 = mid + 1; int end2 = end;int index = begin;       //指向tmp,=begin是 根据要进行比较插入的数组的位置 找到其对应在tmp中所对应的位置,则不会覆盖前面已经排好序的数据//原型:合并两组数,且有序while (begin1 <= end1 && begin2 <= end2) {      //&&其中一组满足了条件就不再继续,就跳出循环if (a[begin1] < a[begin2]) {tmp[index++] = a[begin1++];}else {tmp[index++] = a[begin2++];}}	while (begin1 <= end1) {       //把剩下还没插入tmp的,插入进去tmp[index++] = a[begin1++];}while (begin2 <= end2) {       //把剩下还没插入tmp的,插入进去tmp[index++] = a[begin2++];}//拷贝回原数组//source   dest     拷贝的数组大小memcpy(a+begin,tmp+begin,sizeof(DataType)*(end-begin+1));
}void MergeSort(DataType* a, int n) {DataType* tmp = (DataType*)malloc(sizeof(DataType) * n);     //开辟新的数组(临时存放)用于归并排序过程if (tmp == NULL) {perror("malloc fail");return;}//将 待排序的数组、归并过程用的tmp临时数组、归并范围 传过去_MergeSort(a, tmp, 0, n - 1);         //因为 主函数中有malloc tmp的操作,若递归调用主函数,则每次调用都会malloc,再free 是对空间上的浪费//因此用子函数进行递归 【_子函数】free(tmp);
}


(4)归并排序效率分析

1)时间复杂度 O(N*logN)

二分 有 logN 层 ,也正是因为是logN层,递归深度不会太深,所以不用考虑非递归,当然非递归也能实现。
每层有N个数进行归并排序

=>N*logN
在这里插入图片描述

2)空间复杂度 O(N)

开辟了个 空间大小为N的 新的数组,用于归并有序的过程。
在这里插入图片描述
在原数组上归并会出现什么问题:

  1. 会覆盖数据
  2. 最小的1换到8的位置后,8和7就不再保持有序了。

稳定性:稳定



二、归并排序的非递归实现

归并排序是 二分的思想 => logN层 => 递归不会太深、且现编译器优化后,递归、非递归的性能差距没有那么大了 =>所以不用考虑非递归,但非递归实现也不难。下面带大家简单实现一下。

(1) 关于递归的缺点的讨论

递归的缺点:递归消耗栈帧,递归的层数太深,容易爆栈。
【栈的空间比较小,在x86(32位)环境下,只有8M。(对比同一环境下的堆,则有2G+)。因为平时函数调用开不了多少个栈帧。理论上递归深度>1w 可能就会爆 ,但实际上5k左右就爆掉了】

这时就需要改非递归了

★递归—>非递归

  1. 改循环
  2. 利用 [ 数据结构 ] 栈(本质上是通过malloc 在堆上开辟的内存空间,内存空间足够大)
  3. 递归逆着来求(如斐波那契数列逆着来求也是可行的)【归并排序的非递归实现 也是个很好的例子】
    在这里插入图片描述而归并排序的非递归实现则是用到了其中的第三点 。


(2) 归并排序 非递归算法实现思路

虽说不是递归,是递归的逆序版。是直接从最深层次,逆序回去,直接开始归并排序,免去了向下深入递归。虽说不是递归,但也算是递归的思路的另一个种实现。
在这里插入图片描述

  1. 开辟新的数组(临时存放)用于归并排序过程
  2. int gap=1;gap*=2【gap控制归并的范围:11归并,22归并,44归并】
  3. for (int i = 0; i < n; i += 2 * gap) { 【i 控制进行比较轮到的组号,控制进行归并的组号】
  4. 归并完一轮,将归并好的有序数组拷贝回原数组memcpy 。
  5. 进入新的一轮归并,直至gap>n则归并完成

☆注意的两个情况
6. if (begin2 >= n) { break; } 第二组不存在,这一组不用归并了
7. if (end2 > n) { end2 = n - 1; } 第二组右边界越界问题,修正一下
在这里插入图片描述



(3)码源详解

//归并排序——非递归版 :从最底层开始,逆着往回求(如同斐波那契)
void MergeSortNonR(DataType* a,int n) {DataType* tmp = (DataType*)malloc(sizeof(DataType) * n);     //开辟新的数组(临时存放)用于归并排序过程if (tmp == NULL) {perror("malloc fail");return;}int gap = 1;while (gap < n) {                                        //gap控制 11归并,22归并,44归并//i控制进行比较轮到的组号,控制归并的组号for (int i = 0; i < n; i += 2 * gap) {               //可以通过画出数组,在草稿纸上演示,理清要比较的数begin1、end1、begin2、end2之间和i、gap的数量关系//[begin1,end1][begin2,end2]归并               int begin1 = i; int end1 = i + gap - 1;          //-1 控制下标的边界int begin2 = i + gap; int end2 = i + 2 * gap - 1;//如果第二组不存在,这一组不用归并了if (begin2 >= n) {break;}//第二组右边界越界问题,修正一下if (end2 > n) {end2 = n - 1;}int index = i;while (begin1 <= end1 && begin2 <= end2) {           //&& 其中一组不满足了条件了(其中一个数组遍历完了)就不再继续,就跳出循环  if (a[begin1] < a[begin2]) {                     //两个数组比对,小的放进去tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}while (begin1 <= end1) {                         //把剩下的没遍历进去的数组剩余的部分 遍历进去tmp[index++] = a[begin1++];}while (begin2 <= end2) {tmp[index++] = a[begin2++];}//拷贝回原数组//通过a+i、tmp+i来找到要拷贝数组部分的对应下标memcpy(a + i, tmp + i,(end2-i+1)*sizeof(DataType));}printf("\n");gap *= 2;                                            //gap控制总体归并}free(tmp);
}


(4)运行结果

在这里插入图片描述

相关文章:

【数据结构】归并排序 的递归实现与非递归实现

归并排序 前言一、归并排序递归实现&#xff08;1&#xff09;归并排序的核心思路&#xff08;2&#xff09;归并排序实现的核心步骤&#xff08;3&#xff09;归并排序码源详解&#xff08;4&#xff09;归并排序效率分析1&#xff09;时间复杂度 O&#xff08;N*logN&#xf…...

Go的命令行工具开发:使用Cobra库

今天我们将深入探讨如何使用Go语言和Cobra库来开发命令行工具。 命令行工具在软件开发中有着广泛的应用&#xff0c;它们快速、高效&#xff0c;且易于自动化。 Go语言因其简洁、高效而被广泛用于命令行工具的开发。Cobra库则是Go中用于构建命令行工具的重要库之一。 为什么选…...

坚持#第420天~阿里云轻量服务器内存受AliYunDunMonito影响占用解决方法

阿里云轻量服务器内存受AliYunDunMonito影响占用解决方法&#xff0c;亲测有效&#xff1a; Mobax好卡啊&#xff0c;那就直接在阿里云后台操作即可&#xff0c;阿里云后台也可以上传文件。 Navicat mysql好卡啊&#xff0c;那就直接在阿里云后台最上面帮助的右边有个数据库&…...

时间序列聚类的直观方法

一、介绍 我们将使用轮廓分数和一些距离度量来执行时间序列聚类实验&#xff0c;同时利用直观的可视化&#xff0c;让我们看看下面的时间序列&#xff1a; 这些可以被视为具有正弦、余弦、方波和锯齿波的四种不同的周期性时间序列 如果我们添加随机噪声和距原点的距离来沿 y 轴…...

vue3的reactive源码解析

reactive源码解析 总结一句: reactive是个函数。reactive函数返回了一个createReactiveObject函数&#xff0c;createReactiveObject又返回了一个“经new Proxy实例化”的对象。 详细介绍: 我们使用时传给reactive函数一个对象类型target&#xff0c;reactive又将target传给cr…...

【ElasticSearch系列-04】ElasticSearch的聚合查询操作

ElasticSearch系列整体栏目 内容链接地址【一】ElasticSearch下载和安装https://zhenghuisheng.blog.csdn.net/article/details/129260827【二】ElasticSearch概念和基本操作https://blog.csdn.net/zhenghuishengq/article/details/134121631【三】ElasticSearch的高级查询Quer…...

Redisson初始

最近的自己,一直都在做些老年的技术,没有啥升级,自己也快麻木了,自己该怎么说,那必须行动起来啊!~来来,我们一起增长自己的内功 分布式锁的最强实现: Redisson 1.概念 在介绍之前,我们要知道这个Redisson是啥? 难道就是Redis的son?(我第一次就这么认为的哈哈!) 事实也的确如…...

【华为OD题库-018】AI面板识别-Java

题目 Al识别到面板上有N(1<N≤100)个指示灯&#xff0c;灯大小一样&#xff0c;任意两个之间无重叠。由于AI识别误差&#xff0c;每次识别到的指示灯位置可能有差异&#xff0c;以4个坐标值描述Al识别的指示灯的大小和位置(左上角x1,y1&#xff0c;右下角x2.y2)。请输出先行…...

[概述] 点云滤波器

拓扑结构 点云是一种三维数据&#xff0c;有几种方法可以描述其空间结构&#xff0c;以利于展开搜索 https://blog.csdn.net/weixin_45824067/article/details/131317939 KD树 头文件&#xff1a;pcl/kdtree/kdtree_flann.h 函数&#xff1a;pcl::KdTreeFLANN 作用&#xff1a…...

[笔记] 汉字判断

参考博客&#xff1a;如果判断一个字符是西文字符还是中文字符 结论&#xff1a; 汉字转数字后&#xff0c;会占两位字符位&#xff0c;两位都是负数。 参考下面代码 输入&#xff1a;你 输出&#xff1a;01 #include<bits/stdc.h> using namespace std; int main() {cha…...

Android开发笔记(三)—Activity篇

活动组件Activity 启动和结束生命周期启动模式信息传递Intent显式Intent隐式Intent 向下一个Activity发送数据向上一个Activity返回数据 附加信息利用资源文件配置字符串利用元数据传递配置信息给应用页面注册快捷方式 启动和结束 &#xff08;1&#xff09;从当前页面跳到新页…...

nodejs+vue+python+php在线购票系统的设计与实现-毕业设计

伴随着信息时代的到来&#xff0c;以及不断发展起来的微电子技术&#xff0c;这些都为在线购票带来了很好的发展条件。同时&#xff0c;在线购票的范围不断增大&#xff0c;这就需要有一种既能使用又能使用的、便于使用的、便于使用的系统来对其进行管理。在目前这种大环境下&a…...

基于Taro + React 实现微信小程序半圆滑块组件、半圆进度条、弧形进度条、半圆滑行轨道(附源码)

效果&#xff1a; 功能点&#xff1a; 1、四个档位 2、可点击加减切换档位 3、可以点击区域切换档位 4、可以滑动切换档位 目的&#xff1a; 给大家提供一些实现思路&#xff0c;找了一圈&#xff0c;一些文章基本不能直接用&#xff0c;错漏百出&#xff0c;代码还藏着掖…...

城市内涝解决方案:实时监测,提前预警,让城市更安全

城市内涝积水问题是指城市地区在短时间内遭遇强降雨后&#xff0c;地面积水过多&#xff0c;导致城市交通堵塞、居民生活不便、财产损失等问题。近年来&#xff0c;随着全球气候变化和城市化进程的加速&#xff0c;城市内涝积水问题越来越突出&#xff0c;成为城市发展中的一大…...

编译正点原子LINUXB报错make: arm-linux-gnueabihf-gcc:命令未找到

编译正点原子LINUX报错make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到 1.报错内容2.解决办法3./bin/sh: 1: lzop: not found4.编译成功 1.报错内容 make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到CHK include/config/kernel.releaseCHK include/generat…...

工地现场智慧管理信息化解决方案 智慧工地源码

智慧工地系统充分利用计算机技术、互联网、物联网、云计算、大数据等新一代信息技术&#xff0c;以PC端&#xff0c;移动端&#xff0c;设备端三位一体的管控方式为企业现场工程管理提供了先进的技术手段。让劳务、设备、物料、安全、环境、能源、资料、计划、质量、视频监控等…...

Javaweb之HTML,CSS的详细解析

2. HTML & CSS 1). 什么是HTML ? HTML: HyperText Markup Language&#xff0c;超文本标记语言。 超文本&#xff1a;超越了文本的限制&#xff0c;比普通文本更强大。除了文字信息&#xff0c;还可以定义图片、音频、视频等内容。 标记语言&#xff1a;由标签构成的语言…...

基于python+django+vue开发的酒店预订管理系统 - 毕业设计 - 课程设计

文章目录 源码下载地址项目介绍项目功能界面预览项目备注毕设定制&#xff0c;咨询 源码下载地址 点击这里下载源码 项目介绍 该系统是基于pythondjango开发的酒店预定管理系统。适用场景&#xff1a;大学生、课程作业、毕业设计。学习过程中&#xff0c;如遇问题可在github…...

使用vscode实现远程开发,并通过内网穿透在公网环境下远程连接

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…...

ArrayList集合2

ArrayList集合的一些方法 ⑥chear()从列表中移除所有元素 ⑦.isEmpty()判断列表中是否包含元素&#xff0c;不包含返回true&#xff0c;否则返回false public class Test{public static void main(String[] args){Arraylist<String> list new Arraylist<String>()…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...