排序算法详解(堆,归并,快速排序最简及理解写法)

2023-11-09

十大排序算法和复杂度

常见排序的详解

只讲解真实场景中常用的, 简单的就不分析了大家稍微看一下就行

快速排序

快排的思想主要就是每次把一个位置放好后, 可以把数组分成两半, 递归处理子问题即可

空间复杂度OlogN 分析: 每次都分成两半处理子问题, 可以把数组看成树的节点, 则变成整个递归相当于一棵二叉树树高, 即OlogN

时间复杂度优化后基本稳定在ONlogN了, 这个分析过程不要求掌握比较复杂, 不优化的最差ON2 

    //调用 QuickSort(nums, 0, nums.length - 1)
    
    void QuickSort(int[] nums, int l, int r){
        if(l >= r) return ;
        //idx即放好了这个位置, 下面递归
        int idx = partition(nums, l, r);
        QuickSort(nums, l, idx - 1);
        QuickSort(nums, idx + 1, r);
    }
    //每次把一个数放到他正确的位置
    int partition(int[] nums, int l, int r){
        int midIdx = (l + r) >> 1; //这边主要就是优化一下, 否则每次选左边的话在有序数组中会On2复杂度
        swap(nums, l, midIdx);  //然后把他放到左边
        int pivot = nums[l];
        int i = l + 1, j = r;
        while(true){
            //小于主元的放在左边
            while(i <= j && nums[i] < pivot) i ++;
            //大于主元的放在右边
            while(i <= j && nums[j] > pivot) j --;
            if(i >= j) break;
            swap(nums, i, j);
            i ++; j --;
        }
        //这边是j的原因是因为在上面的过程中, i最后一定停在>=pivot位置, 我们是不能换>pivot的否则错误
        swap(nums, l, j);
        return j;
    }
    void swap(int[] nums, int a, int b){
        int t = nums[a];
        nums[a] = nums[b];
        nums[b] = t;
    }

快排还有另外一种用途就是快速选择

 对于本题可以利用partition来达到ON的一个复杂度, 常规做法为堆排序ONlogK这边就不给出堆排序的代码了

复杂度分析:partition函数是一个N的复杂度, 我们这边是优化过的所以是每次partition后把数组拆成两半,后面就是N/2的复杂度, 加起来就是N+N/2+N/4+N/8+...+1这个公式计算完是ON的复杂度

    public int findKthLargest(int[] nums, int k) {
        //我们可以基于partition每次都可以让一个数字去到排序后的位置, 利用这种思想来
        //进行快速选择, 也就是用快速选择找到第k大的数, 他partition后的位置应该在len - k
        int len = nums.length;
        int target = len - k;
        int l = 0, r = len - 1;
        while(true){
            //把一个位置的元素归位
            int partition = partition(nums, l, r);
            //正好是归到了target位置则他就是第k大
            if(partition == target) return nums[partition];
            //大于这个位置代表我们要找的数字在左边
            else if(partition > target) r = partition - 1;
            //反之右边
            else l = partition + 1;
        }
    }
    public int partition(int[] nums, int l, int r){
        int midIdx = (l + r) >> 1;
        swap(nums, midIdx, l);
        int pivot = nums[l];
        int i = l + 1, j = r;
        while(true){
            while(i <= j && nums[i] < pivot) i ++;
            while(i <= j && nums[j] > pivot) j --;
            if(i >= j) break;
            swap(nums, i, j);
            i ++; j --;
        }
        swap(nums, l, j);
        return j;
    }
    public void swap(int[] nums, int a, int b){
        int t = nums[a];
        nums[a] = nums[b];
        nums[b] = t;
    }

堆排序

堆排序则基于树的思想, 建堆的时间复杂度为ON这个必须注意, 大家很多人都会以为跟log有关系其实是无关的, 想象成一颗巨大的树就可以分析出来了

空间复杂度O1, 因为这个是原地操作的算法

时间复杂度ONlogN, 堆排序的自调节复杂度为OlogN

   void HeapSort(int[] nums){
        int size = nums.length;
        //从最后一个非叶子节点调节
        for(int i = size / 2 - 1; i >= 0; i --){
            adjust(nums, i, size);
        }
        for(int i = size - 1; i >= 1; i --){
            //每次把一个最大的放在最后面, 调节根节点调节完就排序完了
            swap(nums, i, 0);
            //这边可以发现我们每次size都是比前面一次小了1哦
            adjust(nums, 0, i);
        }
    }
​
    void adjust(int[] nums, int root, int size){
        int child = 2 * root + 1;
        while(true){
            //越界跳出
            if(child >= size) break;
            //选大儿子
            if(child + 1 < size && nums[child + 1] > nums[child]) child ++;
            //儿子大就交换
            if(nums[root] <= nums[child]){
                swap(nums, root, child);
                root = child;
                child = 2 * root + 1;
            }
            else break;
        }
    }
​
    void swap(int[] nums, int a, int b){
        int t = nums[a];
        nums[a] = nums[b];
        nums[b] = t;
    }

归并排序

归并排序的思想则为处理递归到最小的粒度数组处理子问题, 子问题合并后想上归合起来继续处理即可

空间复杂度ON, 这边递归栈的高度同快速排序是OlogN, 但是考虑到归并过程的额外数组, 故为On

时间复杂度为ONlogN

    //调用MergeSort(nums, 0, nums.length - 1)
    void MergeSort(int[] nums, int l, int r){
        if(l >= r) return ;
        //对半拆分
        int mid = l + r >> 1;
        MergeSort(nums, l, mid);  //注意这里一定必须右边是mid 否则会出错
        MergeSort(nums, mid + 1, r);
        Merge(nums, l, mid, r);
    }
    void Merge(int[] nums, int l, int mid, int r){
        int i = l,  j = mid + 1;
        int[] temp = new int[r - l + 1];
        int cnt = 0;
        //这里是归并的过程, 就是对比左右两个子数组排序一下
        while(i <= mid && j <= r){
            if(nums[i] < nums[j]) temp[cnt ++] = nums[i ++];
            else temp[cnt ++] = nums[j ++];
        }
        while(i <= mid) temp[cnt ++] = nums[i ++];
        while(j <= r) temp[cnt ++] = nums[j ++];
        for(i = 0; i < temp.length; i ++) nums[l ++] = temp[i];
    }
    void swap(int[] nums, int a, int b){
        int temp = nums[a];
        nums[a] = nums[b];
        nums[b] = temp;
    }

冒泡排序

public void bubbleSort(int[] nums){
        int n = nums.length;
        for(int i = 0; i < n; i++){
            boolean flag = false;
            for(int j = n - 1; j > i;j--){
                if(nums[j - 1] > nums[j]){
                    int temp = nums[j - 1];
                    nums[j - 1] = nums[j];
                    nums[j] = temp;
                    flag = true;
                }
            }
             if(flag == false) return ;
        }
    }

插入排序

    public void insertSort(int[] nums){
        int n = nums.length;
        for(int i = 0; i < n; i++){
            int temp = nums[i];
            int j = i - 1;
            while(j >= 0 && nums[j] > temp){
                nums[j + 1] = nums[j];
                j--;
            }
            nums[j + 1] = temp;
        }
    }

选择排序

    public void selectSort(int[] arr){
        int min;
        for(int i = 0;i<arr.length;i++){
            min = i;
            for(int j = i;j<arr.length;j++){
                if(arr[j] < arr[min]){
                    min = j;
                }
            }
            if(min != i) {
                int temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
            }
        }
    }

桶排序

思想:nums[i] 放到桶里面,对于范围小的好用, 即创建一个int[范围], 然后根据范围取一下就排序完了

总结

主要掌握快速排序, 归并排序, 堆排序就可以, 复杂度必须要会分析!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

排序算法详解(堆,归并,快速排序最简及理解写法) 的相关文章

  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Spring Batch 多线程 - 如何使每个线程读取唯一的记录?

    这个问题在很多论坛上都被问过很多次了 但我没有看到适合我的答案 我正在尝试在我的 Spring Batch 实现中实现多线程步骤 有一个包含 100k 条记录的临时表 想要在 10 个线程中处理它 每个线程的提交间隔为 300 因此在任何时
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • JAXb、Hibernate 和 beans

    目前我正在开发一个使用 Spring Web 服务 hibernate 和 JAXb 的项目 1 我已经使用IDE hibernate代码生成 生成了hibernate bean 2 另外 我已经使用maven编译器生成了jaxb bean
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 斯坦福 NLP - 处理文件列表时 OpenIE 内存不足

    我正在尝试使用斯坦福 CoreNLP 中的 OpenIE 工具从多个文件中提取信息 当多个文件 而不是一个 传递到输入时 它会给出内存不足错误 All files have been queued awaiting termination
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • 总是使用 Final?

    我读过 将某些东西做成最终的 然后在循环中使用它会带来更好的性能 但这对一切都有好处吗 我有很多地方没有循环 但我将 Final 添加到局部变量中 它会使速度变慢还是仍然很好 还有一些地方我有一个全局变量final 例如android Pa
  • 加密 JBoss 配置中的敏感信息

    JBoss 中的标准数据源配置要求数据库用户的用户名和密码位于 xxx ds xml 文件中 如果我将数据源定义为 c3p0 mbean 我会遇到同样的问题 是否有标准方法来加密用户和密码 保存密钥的好地方是什么 这当然也与 tomcat
  • 如何在控制器、服务和存储库模式中使用 DTO

    我正在遵循控制器 服务和存储库模式 我只是想知道 DTO 在哪里出现 控制器应该只接收 DTO 吗 我的理解是您不希望外界了解底层域模型 从领域模型到 DTO 的转换应该发生在控制器层还是服务层 在今天使用 Spring MVC 和交互式
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O
  • 节拍匹配算法

    我最近开始尝试创建一个移动应用程序 iOS Android 它将自动击败比赛 http en wikipedia org wiki Beatmatching http en wikipedia org wiki Beatmatching 两

随机推荐

  • [MySQL]一文带你学明白数据库控制语言——DCL

    前言 嗨咯 小伙伴大家好呀 好几天没见了 周末过得怎么样啊 之前学过的SQL语句不会都忘了吧 如果忘了的话大家可以看一下前几期的文章 本期要学习的是SQL语句中的数据库控制语句 DCL 学习完毕之后MySQL中的SQL语句也就结束了 数据库
  • [388]码云使用说明

    码云如何上传项目 码云上传项目 需要3个步骤 在码云网站建立一个空项目 把这个空项目拉到本地 把自己的项目放到这个空项目里面并提交 1 在码云的页面 点击右上角的加号 2 选择新建项目 3 在跳转的页面简要填写项目信息 除了名称和路径 其它
  • 使用HttpClient下载网页

    Httpclient是一个非常好用的第三方库 用于网络编程 可以用来做个爬虫程序什么之类的 安卓中内置的网络编程库就是httpclient 下面就可大家介绍介绍怎么使用httpclient下载新浪首页的源代码 其过程就是首先构建一个http
  • python怎么调用文件_Python如何调用m文件

    Python如何调用m文件 一 安装Python 并正确配置环境变量 matlab2016a只支持python2 7 python3 3 python3 4 python3 4以上版本不支持 推荐学习 Python教程 二 安装Matlab
  • CSS中如何实现一个自适应正方形(宽高相等)的元素?

    聚沙成塔 每天进步一点点 专栏简介 利用 padding 百分比 2 利用 before 伪元素 写在最后 专栏简介 前端入门之旅 探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅
  • cocos2dx中的内存加载PLIST

    今天 加载图片时有问题 myButtonPList loadTextures jineng 02103 png jineng 02103 light png jineng 03101 png UI TEX TYPE PLIST myButt
  • 时间趋势可视化-柱形图

    第1关 大胃王 比赛数据柱形图绘制 绘制柱形图的基本步骤 本关任务 根据实训提供的 大胃王 比赛数据绘制柱形图 熟悉柱形图绘制的基本步骤 coding utf 8 import pandas as pd from matplotlib im
  • 利用CIBERSORT免疫细胞类群分析详细教程

    利用CIBERSORT免疫细胞类群分析详细教程 现在最火的组学技术是什么 无疑便是单细胞测序了 通过单细胞测序 科研人员可以获得比原来更为精细的细胞图谱 但是单细胞测序诸多限制条件 也是不能让大家很好地利用这项技术解决自己的科学问题 除了较
  • 【Qt】通过QtCreator源码学习Qt(十二):Q_D和Q_Q指针(简称“d指针”)详解

    1 Q D和Q Q指针 简称 d指针 简介 参考博客 https www devbean net 2016 11 qt creator source study 07 https blog csdn net rabinsong articl
  • SpringBoot项目中统计所有Controller中的方法

    对接口方法进行抽象 Data public class ControllerMethodItem public String controllerName public String methodName public String req
  • vscode中preLaunchTask“g++”已终止,退出代码为1的解决方案

    问题背景 楼主原来做的项目 电脑中装了MinGW64 还有MinGW的32位版在用vscode时发现出现了 preLaunchTask g 已终止 退出代码为1的问题 找了好久 解决了问题 launch json 注释的位置 这里修改GDB
  • Vue中实现放大镜效果

    先来看一下我们需要实现的效果是怎样的 这里我们没有使用原生的 js 方法去实现 而是使用的 Vue3 官方推荐的一个工具库 vueuse cor 中的 useMouseInElement 方法来实现放大镜的效果 首先来看一下 useMous
  • 如何安装和配置树莓派

    如何安装和配置树莓派 如果你有一块树莓派的板子 还有一个没安装系统的SD卡 怎么能把系统装上 配置好跑起来 这篇文章主要就讲这个事 这是一块Raspberry Pi Zero W板 以及一个空SD卡 当然 我们需要一个SD卡读卡器 还需要一
  • Flink Native Kubernetes (一)

    目录 文章目录 目录 概述 Linux 集群描述 版本 部署K8S环境 配置Yum 安装docker 安装Rancher 安装K8s 工作集群 添加KubeCtl命令上下文 运行FlinkDemo FlinkSession关于K8s的基础环
  • 三:Sensor SLPI层代码分析---

    三 Sensor SLPI层代码分析 在学习SLPI侧代码前我们先了解下SEE的registry config registry 放在 persist sensors registry registry中 它是通过config生成的 是给S
  • 循环遍历本地的图片使用BASE64编码,并在ajax也遍历图片

    前端调用ajax到后端去图片的方法 并返回 public void search HttpServletRequest request HttpServletResponse response throws Exception String
  • 【毕业设计】基于stm32的智能扫地机器人设计与实现 - 单片机 物联网

    文章目录 0 简介 1 课题背景 2 硬件系统总体框架 2 1 电机驱动 2 2 红外线传感器 2 3 超声波传感器 2 4 MPU6050 2 5 ATK ESP8266 WI FI 模块 2 6 电源管理模块 3 软件系统设计 3 1
  • 前端知识点

    写在前面 CSDN话题挑战赛第1期 活动详情地址 CSDN 参赛话题 前端面试宝典 话题描述 欢迎各位加入话题创作得小伙伴 如果我没有猜错得话 我觉得你是应该同我一样是一位前端人 如今前端在IT事业中的占比越来越重 已经成为不可缺少的部分
  • 2019年DNS服务器速度排行榜

    第一名 DNSPod 不得不说腾讯自从收购了DNSPod后 无论是服务还是速度都有显著的提升 无论是访问速度还是解析速度都在国内是处于龙头大哥的地位 昔日的老大114的地位已经不保 作为腾讯旗下的公司 在游戏解析这一块来说 技术自然是领先于
  • 排序算法详解(堆,归并,快速排序最简及理解写法)

    十大排序算法和复杂度 常见排序的详解 只讲解真实场景中常用的 简单的就不分析了大家稍微看一下就行 快速排序 快排的思想主要就是每次把一个位置放好后 可以把数组分成两半 递归处理子问题即可 空间复杂度OlogN 分析 每次都分成两半处理子问题