Java-数据结构-排序(三) |ू・ω・` )

news2024/11/17 19:52:27

目录

❄️一、归并排序:

              ☞ 基本思想:

             ☞ 代码:

             ☞ 归并排序的非递归方法:

❄️二、排序算法的分析:

 ❄️三、非基于比较的排序:

 ❄️总结:


❄️一、归并排序:

              ☞ 基本思想:

 归并排序是一个建立在归并操作上的一种排序算法,这个算法是采用分治法的典型案例。

 就是:将有序的子序列合并,得到一个完全有序的列表。

       即是先使每个子序列有序,再使子序列段间有序。

   若将两个有序的列表合并成一个列表,称为二路归并。

 我们来看看这个排序是如何进行排序的:

     就是分成了 分解操作 和 合并操作 ,那么我们的这个 分解操作是如何做的,合并操作又是如何做的?我们呢来一一的看看如何操作的:

分解操作:

   1、我们呢对于这个数据 开始位置设置为left ,结束位置设置为 right ,之后求出中间值 mid ,

   2、之后把left 到 mid 下标的值分为一组,mid +1 到 right 的值分为一组。

   3、对于 left 到 mid这一组,再分的话把 mid 的下标给到 right 之后再求 mid 位置。

   4、对于 mid+1 到 right 这一组,再分的话就把 mid+1 的下标给到 left 之后再求 mid 位置。

   5、这样直至我们的 left >= right 的时候结束。

OK,我们的分解思路就是这样的,我们呢来看看代码是如何编写的 :

public static void mergeSort(int[] array) {
        mergeSortTmp(array,0,array.length - 1);
    }

    private static void mergeSortTmp(int[] array, int left, int right) {
        if (left >= right) {
            return;
        }
        //分解操作
        int mid = (left + right) / 2;
        mergeSortTmp(array,left,mid);
        mergeSortTmp(array,mid+1,right);
        
    }

  合并操作:

1、我们在每次分解完一个区间的数据之后呢,就对其进行合并操作,合并之后就是有序的数据了

2、比如我们合并长度为2 的两个有序的数据,就是相当于合并两个有序的数组

3、我们要知道每个数组的开始和结尾

 第一个数组:开头是left 用s1 保存,结尾是mid 用e1 保存

 第二个数组:开头是mid+1 用s2 保存,结尾是right 用e2 保存

4、我们把 s1 和 s2 下标的值进行比较之后小的值呢放到新的数组中,只要有一个超过了e1或者e2就需要退出循环,进行下一步的判断操作。

5、还有判断哪个数组放到新的数组中,之后再把没放入的放进数组中

6、把排好序的数组放到原先的数组中,但是要注意放的时候我们的原数组的下标要加上一个left

     因为我们第二次排序的时候呢下标不是从 0 开始的是从 left 下标开始的。

我们来看看代码是如何编写的: 


    private static void merge(int[] array, int left, int mid, int right) {
        int[] tmp = new int[right - left + 1];
        int k = 0;
        int s1 = left;
        int e1 = mid;
        int s2 = mid + 1;
        int e2 = right;

        while(s1 <= e1 && s2 <= e2) {

            if (array[s1] <= array[s2]) {
                tmp[k++] = array[s1++];
            }else {
                tmp[k++] = array[s2++];
            }
        }

        while (s1 <= e1) {
            tmp[k++] = array[s1++];
        }
        while (s2 <= e2) {
            tmp[k++] = array[s2++];
        }

        for (int i = 0; i < k; i++) {
            array[i+left] = tmp[i];
        }
    }

这就是我们的合并排序的代码了,我们来看看整体的代码:


             ☞ 代码:

 /**
     * 归并排序
     * 时间复杂度:O(N*logN)
     * 空间复杂度:O(N)
     * 稳定性:稳定
     * @param array
     */
    public static void mergeSort(int[] array) {
        mergeSortTmp(array,0,array.length - 1);
    }

    private static void mergeSortTmp(int[] array, int left, int right) {
        if (left >= right) {
            return;
        }
        //分解操作
        int mid = (left + right) / 2;
        mergeSortTmp(array,left,mid);
        mergeSortTmp(array,mid+1,right);
        //每一个分解完之后呢,都要进行排序合并操作
        merge(array,left,mid,right);
    }

    private static void merge(int[] array, int left, int mid, int right) {
        int[] tmp = new int[right - left + 1];
        int k = 0;
        int s1 = left;
        int e1 = mid;
        int s2 = mid + 1;
        int e2 = right;

        while(s1 <= e1 && s2 <= e2) {

            if (array[s1] <= array[s2]) {
                tmp[k++] = array[s1++];
            }else {
                tmp[k++] = array[s2++];
            }
        }

        while (s1 <= e1) {
            tmp[k++] = array[s1++];
        }
        while (s2 <= e2) {
            tmp[k++] = array[s2++];
        }

        for (int i = 0; i < k; i++) {
            array[i+left] = tmp[i];
        }
    }

             ☞ 归并排序的非递归方法:

  我们的非递归呢,就是把我们的分解操作变成非递归的操作,那么如何做呢?

  对于分解操作,我们一开始是不是可以看成它们是 一个一个有序,之后是两个两个有序,之后是四个四个有序,这样下去就可以把我们的分解操实现了。

1、我们定义一个 gap 用来 判断是几个一组的

      我们的 gap 每次变化都是 乘2 的,并且 gap < 数组长度 才可以执行下面的操作

2、我们的定义个 i 从 0 下标开始,我们的 left 就是 i 

    这里我们的 i 不能是++操作进行往下走,我们的 i 这里是 i = i + gap*2

3、mid = left + gap - 1

     在赋值之后呢,我们的mid 要进行判断操作,是否是 >= 数组的长度 ,如果是,就把其进行 - 1

     因为这里我们之后要传给 合并有序数组的操作,防止数组越界

4、right = mid + gap

    这里同样要进行判断操作,是否是 >= 数组的长度 ,如果是,就把其进行 - 1

 

 代码:

public static void mergeSort(int[] array) {
        mergeSortNor(array);
    }

private static void mergeSortTmp(int[] array, int left, int right) {
        if (left >= right) {
            return;
        }
        //分解操作
        int mid = (left + right) / 2;
        mergeSortTmp(array,left,mid);
        mergeSortTmp(array,mid+1,right);
        //每一个分解完之后呢,都要进行排序合并操作
        merge(array,left,mid,right);
    }
//非递归实现归并
public static void mergeSortNor(int[] array) {
        int gap = 1;
        while (gap < array.length) {
            for (int i = 0; i < array.length; i = i + gap*2) {
                int left = i;
                int mid = left + gap - 1;
                if (mid >= array.length) {
                    mid = array.length - 1;
                }
                int right = mid + gap;
                if (right >= array.length) {
                    right = array.length - 1;
                }
                merge(array,left,mid,right);
            }
            gap *= 2;
        }
    }


❄️二、排序算法的分析:

排序方法最好平均最坏(时间复杂度)空间复杂度稳定性
冒泡排序O(N^2)O(N^2)O(N^2)O(1)稳定
插入排序O(N)O(N^2)O(N^2)O(1)稳定
选择排序O(N^2)O(N^2)O(N^2)O(1)不稳定
希尔排序O(N)O(N^1.3)O(N^1.5)O(1)不稳定
堆排序O(N*logN)O(N*logN)O(N*logN)O(1)不稳定
快速排序O(N*logN)O(N*logN)O(N^2)O(log(N))~O(N)不稳定
归并排序O(N*logN)O(N*logN)O(N*logN)O(N)稳定

 ❄️三、非基于比较的排序:

     我们之前介绍的排序都是需要比较的排序方法,我们还有不需要比较的排序方法:计数排序、基数排序、桶排序。

我们的非基于比较的排序可以通过 “传送门” 来了解:

基数排序:

              基数排序

桶排序:

              桶排序

当然如果需要 计数排序的 传送门 的话,这里也有:

              计数排序

 


 ❄️总结:

      OK,到这里呢我们的排序呢就结束了,这次关于排序的代码呢还是比较多的,要认真的理解它们,同时要画图的去理解它们的执行流程。 下一篇博客呢我们就要介绍关于Map与Set的知识啦,让我们尽情期待吧!!!拜拜~~~

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

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

相关文章

在一个.NET Core项目中使用RabbitMQ进行即时消息管理

为了在一个.NET Core项目中使用RabbitMQ进行即时消息管理&#xff0c;以下是详细的全程操作指南&#xff0c;包括安装、配置、编写代码和调试使用。 一、安装RabbitMQ 1. 安装Erlang RabbitMQ依赖Erlang&#xff0c;因此需要先安装Erlang。 Windows: 下载并运行Erlang安装…

人工智能-机器学习-深度学习-分类与算法梳理

目前人工智能的概念层出不穷&#xff0c;容易搞混&#xff0c;理清脉络&#xff0c;有益新知识入脑。 为便于梳理&#xff0c;本文只有提纲&#xff0c;且笔者准备仓促&#xff0c;敬请勘误&#xff0c;不甚感激。 请看右边目录索引 。 人工智能 三大派系 符号主义(Symbolists…

[附源码]宠物领养管理系统+SpringBoot

今天带来一款优秀的项目&#xff1a;宠物领养管理系统源码 。 系统采用的流行的前后端分离结构&#xff0c;内含功能包括"管理端"&#xff0c;“用户领养端”&#xff0c;“宠物管理”&#xff0c;“权限登录”等功能。 如果您有任何问题&#xff0c;也请联系小编&a…

keepalived+lvs集群

目录 一、环境 二、配置 1、master 1.在master上安装配置Keepalived 2.在master上修改配置文件 2、backup 1.在backup&#xff08;192.168.229.12&#xff09;上安装keepalived 2.在backup上修改配置文件 3、master和backup上启动服务 4、web服务器配置 1.web1和web…

使用Java基于GeoTools读取Shapefile矢量数据属性信息-以某市POI数据为例

前言 在之前的博客中&#xff0c;我们讲过在GDAL中如何读取空间数据的属性和数据信息&#xff0c;也简单的讲过如何在GeoTools中读取Shapefile文件的属性信息和数据信息。对于空间矢量数据库&#xff0c;就像我们传统的二维数据库的表字段和表数据的关系&#xff0c;在研究表数…

BERT训练之数据集处理(代码实现)

目录 1读取文件数据 2.生成下一句预测任务的数据 3.预测下一个句子 4.生成遮蔽语言模型任务的数据 5.从词元中得到遮掩的数据 6.将文本转化为预训练数据集 7.封装函数类 8.调用 import os import random import torch import dltools 1读取文件数据 def _read_wiki(data_d…

Java框架学习(Spring)(ioc)(01)

简介&#xff1a;以本片记录在尚硅谷学习ssm-spring-ioc时遇到的小知识 详情移步&#xff1a;想参考的朋友建议全部打开相互配合学习&#xff01; 视频&#xff1a; 014-spring-框架概念理解_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1AP411s7D7?p14&vd_sou…

SpringBoot框架在文档管理中的创新应用

第3章 系统分析 3.1 需求分析 在线文档管理系统主要是为了提高工作人员的工作效率和更方便快捷的满足员工&#xff0c;更好存储所有数据信息及快速方便的检索功能&#xff0c;对系统的各个模块是通过许多今天的发达系统做出合理的分析来确定考虑员工的可操作性&#xff0c;遵循…

峟思助力堤防工程安全:构建多功能防洪屏障

堤防工程&#xff0c;作为水利建设中至关重要的防护体系&#xff0c;不仅守护着江河、湖泊及滨海区域的安全&#xff0c;更是确保人民生命财产安全的坚固防线。在现代社会&#xff0c;随着技术的进步与安全意识的提升&#xff0c;堤防工程不仅限于传统的防洪功能&#xff0c;更…

SpringBoot和JPA初探

目录 SpringBoot和JPA初探0.准备条件1.创建JPA项目2.项目3.总结 SpringBoot和JPA初探 我们使用SpringBootJPA做一个简单的API接口演示&#xff0c;通过一个简单的例子让大家对Spring Data JPA有一个整体的认知。 0.准备条件 IntelliJ IDEAjdk 1.8mysql 8.0maven 3.8.x 1.创…

代码随想录算法训练营第三十九天 | 198.打家劫舍 ,213.打家劫舍II,337.打家劫舍III

第三十九天打卡&#xff0c;今天解决打家劫舍系列问题&#xff0c;树形dp比较难。 198.打家劫舍 题目链接 解题过程 dp[i]&#xff1a;考虑下标i&#xff08;包括i&#xff09;以内的房屋&#xff0c;最多可以偷窃的金额为dp[i]。 要么不偷这一间&#xff0c;那就是前面那间…

开源链动 2+1 模式、AI 智能名片与 S2B2C 商城小程序:以问题解决为导向的盈利新模式

摘要&#xff1a;本文探讨了问题解决盈利模式的重要性&#xff0c;并结合开源链动 21 模式、AI 智能名片以及 S2B2C 商城小程序等创新工具&#xff0c;阐述了如何以用户为中心&#xff0c;通过深刻洞察用户需求&#xff0c;解决用户问题&#xff0c;实现盈利增长。强调了在当今…

[利用python进行数据分析01] “来⾃Bitly的USA.gov数据” 分析出各个地区的 windows和非windows用户

2011 年&#xff0c; URL 缩短服务 Bitly 跟美国政府⽹站 USA.gov 合作&#xff0c;提供 了⼀份从⽣成 .gov 或 .mil 短链接的⽤户那⾥收集来的匿名数据。 在 2011 年&#xff0c;除实时数据之外&#xff0c;还可以下载⽂本⽂件形式的每⼩时 快照。 数据集下载&#xff1a;通…

LabVIEW项目编码器选择

在LabVIEW项目中&#xff0c;选择增量式&#xff08;Incremental Encoder&#xff09;和绝对式&#xff08;Absolute Encoder&#xff09;编码器取决于项目的具体需求。增量式编码器和绝对式编码器在工作原理、应用场景、精度和成本等方面存在显著差异。以下从多方面详细阐述两…

通过service访问Pod

假设Pod中的容器可能因为各种原因发生故障而死掉&#xff0c;Deployment等controller会通过动态创建和销毁Pod来保证应用整体的健壮性&#xff0c;换句话说&#xff0c;Pod是脆弱的&#xff0c;但应用是健壮的 每个Pod都有自己的Ip&#xff0c;当controller用新的Pod替代发生故…

SDK(2 note)

复习上一次内容&#xff1a; 把前一次笔记中的代码&#xff0c;简写一下 #include <windows.h> #include<tchar.h> #include <stdio.h> #include <strsafe.h> VOID showerrormassage() {LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFF…

TS-AI:一种用于多模态个体化脑区划分的深度学习管道,并结合任务对比合成|文献速递-Transformer架构在医学影像分析中的应用

Title 题目 TS-AI: A deep learning pipeline for multimodal subject-specific parcellation with task contrasts synthesis TS-AI&#xff1a;一种用于多模态个体化脑区划分的深度学习管道&#xff0c;并结合任务对比合成 01 文献速递介绍 人类大脑在结构和功能组织上表…

nfs版本问题导致挂载失败

一、系统环境 环境版本操作系统Linux Mint 22 Wilma内核版本6.8.0-44-genericgcc 版本arm-none-linux-gnueabihf-gcc (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10)) 9.2.1 20191025uboot 版本2020.01开发板Linux版本5.4.31 二、问题描述 内核通过…

拒绝信息泄露!VMD滚动分解 + Informer-BiLSTM并行预测模型

前言 在时间序列预测任务中&#xff0c;像 EMD&#xff08;经验模态分解&#xff09;、CEEMDAN&#xff08;完全集合经验模态分解&#xff09;、VMD&#xff08;变分模态分解&#xff09; 等分解算法的使用有可能引入信息泄露&#xff0c;具体情况取决于这些方法的应用方式。信…

通过WebTopo在ARMxy边缘计算网关上实现系统集成

随着工业互联网技术的发展&#xff0c;边缘计算成为了连接物理世界与数字世界的桥梁&#xff0c;其重要性日益凸显。边缘计算网关作为数据采集、处理与传输的核心设备&#xff0c;在智能制造、智慧城市等领域发挥着关键作用。 1. BL340系列概述 BL340系列是基于全志科技T507-…