一篇文章带你了解归并排序-分治法

news2024/11/28 12:52:17

文章目录

    • 两个有序数组排序
    • 一个局部有序数组排序
    • 分治法
    • 归并排序

两个有序数组排序

        先来一个场景假设,先有两个有序数组{1,3,5,9}、{2,4,6,8},要求合并成一个有序数组。
我们先上一段简单的处理代码

    public static int[] merge(int[] leftArr, int[] rightArr) {
        int[] res = new int[leftArr.length + rightArr.length];
        //定义a、b、res数组的初始下标位
        int i=0, j=0, k=0;
        while(i < leftArr.length && j < rightArr.length) {
            if (leftArr[i] > rightArr[j]) {
                res[k] = rightArr[j];
                j++;
            }else {
                res[k] = leftArr[i];
                i++;
            }
            k++;
            System.out.println("第"+k+"次比较后当前数组:"+Arrays.toString(res));
        }
        if (i < leftArr.length) {
            res[k] = leftArr[i];
        }
        if (j < rightArr.length) {
            res[k] = rightArr[j];
        }
        System.out.println("最后数组:"+Arrays.toString(res));
        return res;
    }

输出结果:

1次比较后当前数组:[1, 0, 0, 0, 0, 0, 0, 0]2次比较后当前数组:[1, 2, 0, 0, 0, 0, 0, 0]3次比较后当前数组:[1, 2, 3, 0, 0, 0, 0, 0]4次比较后当前数组:[1, 2, 3, 4, 0, 0, 0, 0]5次比较后当前数组:[1, 2, 3, 4, 5, 0, 0, 0]6次比较后当前数组:[1, 2, 3, 4, 5, 6, 0, 0]7次比较后当前数组:[1, 2, 3, 4, 5, 6, 8, 0]
最后数组:[1, 2, 3, 4, 5, 6, 8, 9]

        乍一看好像没有问题,牛逼666。如果把数组变成{1,3,5,9,10}、{2,4,6,8},我们再运行一下

1次比较后当前数组:[1, 0, 0, 0, 0, 0, 0, 0, 0]2次比较后当前数组:[1, 2, 0, 0, 0, 0, 0, 0, 0]3次比较后当前数组:[1, 2, 3, 0, 0, 0, 0, 0, 0]4次比较后当前数组:[1, 2, 3, 4, 0, 0, 0, 0, 0]5次比较后当前数组:[1, 2, 3, 4, 5, 0, 0, 0, 0]6次比较后当前数组:[1, 2, 3, 4, 5, 6, 0, 0, 0]7次比较后当前数组:[1, 2, 3, 4, 5, 6, 8, 0, 0]
最后数组:[1, 2, 3, 4, 5, 6, 8, 9, 0]

        right数组最后一位:10没赋值进去。while循环了7次,最后i=3,j=3时:判断 9 > 8 将res[6] = 8,j++后j=4不满足循环条件,在 if (i < leftArr.length) 处 res[7] = 9,结束了,怎么处理?看清题目条件:两个“有序”数组,leftArr[i] > rightArr[j],那么leftArr[i+1] > rightArr[j]。ok问题解决,那就把if改成while,如下:

public static int[] merge(int[] leftArr, int[] rightArr) {
        int[] res = new int[leftArr.length + rightArr.length];
        //定义a、b、res数组的初始下标位
        int i=0, j=0, k=0;
        while(i < leftArr.length && j < rightArr.length) {
            if (leftArr[i] > rightArr[j]) {
                res[k] = rightArr[j];
                j++;
            }else {
                res[k] = leftArr[i];
                i++;
            }
            k++;
            System.out.println("第"+k+"次比较后当前数组:"+Arrays.toString(res));
        }
        //将if条件改成while
        while (i < leftArr.length) {
            res[k] = leftArr[i];
            k++;
            i++;
        }
        while (j < rightArr.length) {
            res[k] = rightArr[j];
            k++;
            j++;
        }
        System.out.println("最后数组:"+Arrays.toString(res));
        return res;
    }

输出

1次比较后当前数组:[1, 0, 0, 0, 0, 0, 0, 0, 0]2次比较后当前数组:[1, 2, 0, 0, 0, 0, 0, 0, 0]3次比较后当前数组:[1, 2, 3, 0, 0, 0, 0, 0, 0]4次比较后当前数组:[1, 2, 3, 4, 0, 0, 0, 0, 0]5次比较后当前数组:[1, 2, 3, 4, 5, 0, 0, 0, 0]6次比较后当前数组:[1, 2, 3, 4, 5, 6, 0, 0, 0]7次比较后当前数组:[1, 2, 3, 4, 5, 6, 8, 0, 0]
最后数组:[1, 2, 3, 4, 5, 6, 8, 9, 10]

一个局部有序数组排序

        两个有序数组合并解决了,我们再提出下一个问题,按照上面的思路把一个数组{1,3,5,9,10,2,4,6,8},变成有序数组。
代码如下:

    public static void merge(int[] arr) {
        //将数组拆分成两个
        int mid = (arr.length - 1) / 2;
        int[] leftArr = Arrays.copyOfRange(arr,0,mid+1);
        int[] rightArr = Arrays.copyOfRange(arr,mid+1,arr.length);
        //定义左右数组初始位
        int i=0,j=0,k=0;
        while(i < leftArr.length && j < rightArr.length) {
            if (leftArr[i] > rightArr[j]) {
                arr[k] = rightArr[j];
                j++;
            }else {
                arr[k] = leftArr[i];
                i++;
            }
            k++;
            System.out.println("第"+k+"次比较后当前数组:"+Arrays.toString(arr));
        }
        //将if条件改成while条件
        while (i < leftArr.length) {
            arr[k] = leftArr[i];
            k++;
            i++;
        }
        while (j < rightArr.length) {
            arr[k] = rightArr[j];
            k++;
            j++;
        }
        System.out.println("最后数组:"+Arrays.toString(arr));
    }

输出:

1次比较后当前数组:[1, 3, 5, 9, 10, 2, 4, 6, 8]2次比较后当前数组:[1, 2, 5, 9, 10, 2, 4, 6, 8]3次比较后当前数组:[1, 2, 3, 9, 10, 2, 4, 6, 8]4次比较后当前数组:[1, 2, 3, 4, 10, 2, 4, 6, 8]5次比较后当前数组:[1, 2, 3, 4, 5, 2, 4, 6, 8]6次比较后当前数组:[1, 2, 3, 4, 5, 6, 4, 6, 8]7次比较后当前数组:[1, 2, 3, 4, 5, 6, 8, 6, 8]
最后数组:[1, 2, 3, 4, 5, 6, 8, 9, 10]

        我们将原数组拆分后,将左右两个数组作为输入源,原arr数组变成输出源,运行正常没有问题。

分治法

        通过上面代码的铺垫,下面简单说一下分治法。分治法顾名思义:分而治之,因为许多算法在结构上是具有递归性的,解决一个给定的问题,算法一次或者多次递归调用其自身,将问题变成类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。
分治法每层递归都有三个步骤:
分解: 将原问题分解成若干子问题
解决: 解决这些子问题,子问题规模大就再递归求解,规模小直接求解。
合并: 合并这些子问题的解成为原问题的解。

归并排序

        归并排序完全遵循分治法,以刚才的问题为例{1,3,5,9,10,2,4,6,8},想要使用以上代码求解,需要保证{1,3,5,9,10}、{2,4,6,8}有序,那{1,3,5,9,10}有序的前提需要保证{1,3,5}、{9,10}有序。现在将数组打乱:{3,1,9,6,2,10,8,4,5},归并排序的处理思想,如下图所示:
在这里插入图片描述

理解上面这张图,加上之前的铺垫,差不多就可以手搓代码解决问题了。

    public static void main(String[] args) {
        int[] arr = new int[]{3,1,9,6,2,10,8,4,5};
        mergeSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    public static void mergeSort(int[] arr, int low, int high) {
        if (low < high) {
            int mid = low + (high - low) / 2;
            mergeSort(arr,low,mid);
            mergeSort(arr,mid+1,high);
            merge(arr,low,mid,high);
        }
    }
	public static void merge(int[] arr, int low, int mid,int high) {
        //将数组拆分成两个
        int[] leftArr = Arrays.copyOfRange(arr,low,mid+1);
        int[] rightArr = Arrays.copyOfRange(arr,mid+1,high+1);
        //定义左右数组初始位,注意k的值要从low开始
        int i=0,j=0,k=low;
        while(i < leftArr.length && j < rightArr.length) {
            if (leftArr[i] > rightArr[j]) {
                arr[k] = rightArr[j];
                j++;
            }else {
                arr[k] = leftArr[i];
                i++;
            }
            k++;
        }
        //将if条件改成while条件
        while (i < leftArr.length) {
            arr[k] = leftArr[i];
            k++;
            i++;
        }
        while (j < rightArr.length) {
            arr[k] = rightArr[j];
            k++;
            j++;
        }
    }

当然merge方法中的数组拆分可以物理分,也可以逻辑分,为了便于循序渐进,便于理解。下面我把逻辑分代码附上,顺便缩减一下代码。

    public static void merge2(int[] arr, int low, int mid,int high) {
        int[] res = new int[high - low + 1];
        //定义左右数组初始位
        int i=low, j=mid+1, k=0;
        while(i <= mid && j <= high) {
            res[k++] = arr[i] > arr[j] ? arr[j++] : arr[i++];
        }
        while (i <= mid) {
            res[k++] = arr[i++];
        }
        while (j <= high) {
            res[k++] = arr[j++];
        }
        //赋值到原数组
        int r=0,s=low;
        while(s <= high) {
            arr[s++] = res[r++];
        }
    }

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

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

相关文章

Redis后台线程之非阻塞删除

当Redis执行删除命令的时候&#xff0c;如果被删除的对象是列表、集合、散列类型&#xff0c;因为这些数据类型包含的元素存放在不同的内存块中&#xff0c;redis需要遍历所有元素来释放其对应的内存块空间&#xff0c;这个耗时操作可能导致redis阻塞&#xff0c;redis4提供的U…

[数据集][目标检测]agvs仓储机器人检测数据集VOC+YOLO格式967张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;967 标注数量(xml文件个数)&#xff1a;967 标注数量(txt文件个数)&#xff1a;967 标注类别…

API接口安全101:基础概念与最佳实践

文章目录 API定义协议架构风格描述语言 Webservicewsdl介绍复现 SOAPswagger介绍指纹查找利用存在目录复现 HTTPWebpack介绍复现 在当今数字化时代,API接口已成为现代软件架构中不可或缺的组成部分。它们连接着各种应用程序和服务,促进了数据交换和功能集成。然而,随着API的普及…

【PyTorch】神经网络的基本骨架-nn.Module的使用以及convolution-layers卷积层介绍

前提文章目录 【PyTorch】深度学习PyTorch环境配置及安装【详细清晰】 【PyTorch】深度学习PyTorch加载数据 【PyTorch】关于Tensorboard的简单使用 【PyTorch】关于Transforms的简单使用 【PyTorch】关于torchvision中的数据集以及dataloader的使用 文章目录 前提文章目录nn.…

从易车“超级818冠军之夜” 看如何借势体育营销点燃汽车消费热潮

编辑 | 魏力 发布 | 大力财经 导语&#xff1a;这个8月&#xff0c;是属于奥运的8月。 巴黎奥运会虽圆满落幕&#xff0c;但属于奥运健儿们的热度还在持续。在这股奥运热潮的带动下&#xff0c;全民运动热情持续释放&#xff0c;同时也激发出巨大的消费潜力。 赛场外&#…

Go 1.23中值得关注的几个变化

距离上一次Go 1.22版本发布[1]又过去六个月了&#xff0c;我们如期迎来了Go 1.23版本的发布](https://mp.weixin.qq.com/s/IpDUOe0AUDKW2PYCWmvLYw)。 对于Go项目乃至整个Go社区而言&#xff0c;这个版本还有一点额外的意义&#xff0c;那就是这是Russ Cox[2]作为Tech lead&…

nginx 日志格式化,每日分割文件(已亲测)

首先nginx版本是1.23.4&#xff0c;在安装目录的conf文件夹下&#xff0c;配置nginx.conf。配置如下&#xff1a; logformat 代表日志格式设置 frmain 代表日志配置别名 map 行代表设置每日切割文件格式 需要在配置文件location指定访问的路径下&#xff0c;配置日志输出路径…

AI自动生成PPT怎么用?5大AI生成PPT技巧教会你

处暑悄然而至&#xff0c;标志着炎热夏季的逐渐远去&#xff0c;自然界的万物开始步入收获与沉淀的季节。值此节气更迭之际&#xff0c;何不借助现代科技的力量&#xff0c;用一份精美的PPT来宣传处暑的独特魅力&#xff1f; 无需繁琐制作&#xff0c;AI生成PPT免费工具就能助…

C学习(数据结构)-->实现链式结构二叉树

目录 一、链式二叉树结构 二、实现 1、申请新结点 2、前、中、后序遍历 1&#xff09;前序遍历 例&#xff1a; 2&#xff09;中序遍历 3&#xff09;后序遍历 3、结点个数 1&#xff09;二叉树结点个数 例&#xff1a;​编辑 2&#xff09;二叉树叶子结点个数 3&…

C++入门基础知识27

成长路上不孤单&#x1f60a;【14后小学生一枚&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff08;&#xff01;&#xff01;&#xff01…

工厂老板、设计师怎么选通风采光天窗?重点关注哪些方面?

选通风采光天窗首先看预算与通风采光需求&#xff0c;然后看品牌和售后&#xff0c;选购过程中重点关注天窗的型号、规格尺寸、材料配置、外观造型及颜色。一、预算与通风采光需求 通风采光天窗已成为厂房建筑上必备的屋顶设备&#xff0c;现目前天窗的型号多样&#xff0c;价位…

原神4.8版本重点培养和抽到角色数据表:修改了添加倒计时.隐藏了抽到角色数据表删除按钮、备注列和选择列

<!DOCTYPE html> <html lang"zh-cn"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>原神4.8版本抽到角色和重点培养数据表</title…

七牛云 CDN 视频瘦身,为视频分发「减负增效」

随着智能设备的普及&#xff0c;以及各种以分享视频为主的平台的兴起&#xff0c;人们记录生活、分享故事的方式不再局限于文字和图片&#xff0c;而是越来越多地通过视频来表达。视频也不再需要复杂的制作过程&#xff0c;变得随手可得。 然而&#xff0c;视频在互联网上的爆炸…

mac os 外接设备使用win习惯快捷键

目录 1. 简单映射版本&#xff08;常用快捷键&#xff09;2. 如果想追求完全的win匹配3. 关于外接鼠标滚动设置 1. 简单映射版本&#xff08;常用快捷键&#xff09; 就把ctrl和Command键互换一下就行 点击设置-键盘-键盘快捷键 然后在修饰键中&#xff0c;将control和comm…

怎么恢复电脑删除的文件?全面指南助你找回宝贵数据

在数字化时代&#xff0c;电脑中的文件承载着我们的工作成果、学习资料、珍贵照片以及无数回忆。然而&#xff0c;不小心删除重要文件的情况时有发生&#xff0c;让人心急如焚。别担心&#xff0c;本文将为你提供一份全面的指南&#xff0c;教你如何恢复电脑中删除的文件&#…

虚幻5|AI视力系统,听力系统,预测系统(2)听力系统

虚幻5|AI视力系统&#xff0c;听力系统&#xff0c;预测系统&#xff08;1&#xff09;视力系统-CSDN博客 一&#xff0c;把之前的听力系统&#xff0c;折叠成函数&#xff0c;复制粘贴一份改名为听力系统 1.小个体修改如下&#xff0c;把之前的视力系统改成听力系统 2.整体修…

Java—Lambda表达式

注意&#xff1a;如果无法判断一个方法是否为函数式接口&#xff0c;可以查看该方法的源码中是否携带FunctionalInterface注解。 lambda表达式再简化写法规则如下。 1. 参数类型可以省略不写 2. 如果只有一个参数&#xff0c;参数的 "( )" 也可以省略。 3. 如果Lambd…

使用Java和XPath在XML文档中精准定位数据

在当今数据驱动的世界中&#xff0c;能够从复杂的文档结构中准确地提取信息是一项极具价值的技能。XML文档因其结构化和可扩展性广泛用于各种应用中&#xff0c;而XPath则是一种强大而灵活的语言&#xff0c;专门用于在这些文档中进行导航和数据提取。本篇文章将带您深入了解如…

Android Studio 动态表格显示效果

最终效果 一、先定义明细的样式 table_row.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_h…

【YOLO家族】Scaled-YOLOv4, Optimal Speed and Accuracy of Object Detection,CVPR 2021

资源 论文题目《YOLOv4: Optimal Speed and Accuracy of Object Detection》 论文地址&#xff1a;https://arxiv.org/abs/2004.10934 论文代码&#xff1a;https://github.com/AlexeyAB/darknet 作者&#xff1a;AlexeyAB 论文链接&#xff1a;https://arxiv.org/pdf/2004.10…