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

归并排序的递归和非递归实现

归并排序的本质是 “分治”:

把大数组拆成小数组,各自排好序后,再合并成一个有序数组。

就像把一堆乱牌分成两半,每半先理好,再把两堆理好的牌一张张比对,按顺序合成一堆 —— 这就是 “分” 和 “合” 的过程。

下面看一道Leetcode题:
在这里插入图片描述

递归实现

public class Main {public static int[] sortArray(int[] nums){// 数组长度大于1时才需要排序(长度为0或1默认有序)if(nums.length>1){mergeSort(nums);}return nums;}// 定义最大数组长度public static int MAXN = 50001;// 辅助数组:用于归并过程中临时存储元素,避免每次合并都新建数组public static int[] help = new int[MAXN];public static void mergeSort(int[] arr){// 从数组的0号位置到最后一个位置(arr.length-1)进行排序sort(arr,0,arr.length-1);}public static void sort(int[] arr,int l,int r){// 当区间只有一个元素时(l==r),无需排序,直接返回if(l==r){return;}// 计算中间位置(等价于(l+r)/2,但用位运算>>1避免溢出,且效率更高)int m = l + ((r - l) >> 1);// 递归排序左半区间 [l, m]sort(arr,l,m);// 递归排序右半区间 [m+1, r]sort(arr,m+1,r);// 合并左右两个已排序的区间merge(arr,l,m,r);}public static void merge(int[] arr,int l,int m,int r){int i = l;       // 辅助数组help的当前填充位置(从l开始)int a = l;       // 左区间的遍历指针(从l开始)int b = m + 1;   // 右区间的遍历指针(从m+1开始)// 1. 双指针遍历左右区间,将较小的元素依次放入helpwhile(a <= m && b <= r){// 谁小就先放谁,相等时优先放左区间元素(保证稳定性)help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++];}// 2. 左区间还有剩余元素,全部放入help(右区间已遍历完)while(a <= m){help[i++] = arr[a++];}// 3. 右区间还有剩余元素,全部放入help(左区间已遍历完)while(b <= r){help[i++] = arr[b++];}// 4. 将help中排序好的元素拷贝回原数组的[l, r]区间for(i = l; i <= r; i++){arr[i] = help[i];}}}

非递归实现

public class Main {public static int[] sortArray(int[] nums){if(nums.length>1){mergeSort(nums);}return nums;}public static int MAXN = 50001;public static int[] help = new int[MAXN];public static void mergeSort(int[] arr){int n = arr.length;// step:当前要合并的子数组长度,初始为1(单个元素默认有序),每次翻倍(左移1位等价于×2)// 循环条件:step < n(当子数组长度超过数组长度时,排序完成)for(int step=1; step < n; step <<= 1){int l = 0; // 每次合并的起始位置,从0开始// 遍历数组,按当前step划分并合并子数组while(l < n){// m:左子数组的结束位置(左子数组范围 [l, m],长度为step)int m = l + step - 1;// 若右子数组起始位置(m+1)已超出数组范围,说明只剩一个子数组,无需合并if(m + 1 >= n){break;}// r:右子数组的结束位置(右子数组最大长度为step,取较小值避免越界)int r = Math.min(l + (step << 1) - 1, n - 1);// 合并 [l, m] 和 [m+1, r] 两个有序子数组merge(arr, l, m, r);// 移动到下一组子数组的起始位置l = r + 1;}}}public static void merge(int[] arr,int l,int m,int r){int i=l;int a = l;int b = m+1;while(a<=m&&b<=r){help[i++]=arr[a]<=arr[b]?arr[a++]:arr[b++];}while(a<=m){help[i++]=arr[a++];}while(b<=r){help[i++]=arr[b++];}for(i=l;i<=r;i++){arr[i]=help[i];}}}

代码文件
链接:https://pan.quark.cn/s/fc867494224a
提取码:9nSb

http://www.dtcms.com/a/434778.html

相关文章:

  • 天津建设网站个人主页网页设计模板免费
  • 整体设计 逻辑系统程序 之8 三种逻辑表述形式、形式化体系构建及关联规则(正则 / 三区逻辑)
  • 京东Java后台开发面试题及参考答案(上)
  • 婚纱摄影网站帮忙建设公司网站
  • 载具系统介绍
  • 理解采样操作的不可微性及重参数化技巧
  • 做网站 视频外链做网站的做网站麻烦吗
  • TOGAF之架构标准规范-需求管理
  • 临沂 企业网站建设seo双标题软件
  • 公司为什么做网站支付宝小程序
  • Linux中读写自旋锁rwlock的实现
  • 前端-JS基础-day5
  • 字体版权登记网站WordPress网站结构优化
  • [特殊字符]【保姆级教程】GLM-4.6 接入 Claude Code:200K 长上下文 + Agentic Coding,开发者福音!编程能力大幅提升!
  • 大前端开发技术知识框架详解、Mono repo工程化实践详解、微前端实践详解
  • MDK编译过程
  • 网站整体风格设计ios aso优化工具
  • 数据结构KMP算法详解:C语言实现
  • 【网络通讯安全认证的理解:从密钥签名、数字证书到 HTTPS/TLS 流程】
  • 蜘蛛抓取网站模块原理推广是怎么做的
  • 中国石油AI中台-昆仑大模型介绍(二)
  • RAG核心特性:查询增强和关联
  • Spring 中事务的实现
  • 苏州哪家公司做网站网站布局是什么
  • AI智能体在研究分析中的仿真应用:预测、生存与建构——情绪是基于趋利避害的预测机制吗?
  • 12.排序(上)
  • Java bean 数据校验
  • 级数敛散性判别:泰勒展开与等价无穷小的正确使用
  • gRPC从0到1系列【13】
  • 笔记本 光驱 的内部结构及用法: 应急系统启动 (恢复) 光盘 (DVD+R/RW)