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

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(使用前将#替换为@)

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

  • 菜单未显示在应用程序中

    由于某种原因 我的操作菜单在我的 Android Studio 应用程序中消失了 我正在按照教程学习如何创建 Android 应用程序 但最终遇到了这个问题 我正在使用 atm 的教程 http www raywenderlich com
  • 热重载在docker中运行的java程序

    我开发了一个java程序 应该在docker中运行 然而 我在调试docker中运行的java程序时遇到了很多痛苦 我在网上搜索 一些教程提出了像 spring dev tools 这样的工具 因为我的java程序是基于spring boo
  • 解决错误:日志已在具有多个实例的atomikos中使用

    我仅在使用atomikos的实时服务器上遇到问题 在我的本地服务器上它工作得很好 我在服务器上面临的问题是 init 中出错 日志已在使用中 完整的异常堆栈跟踪 java lang RuntimeException Log already
  • JNI 不满意链接错误

    我想创建一个简单的 JNI 层 我使用Visual studio 2008创建了一个dll Win 32控制台应用程序项目类型 带有DLL作为选项 当我调用本机方法时 出现此异常 Exception occurred during even
  • Java8无符号算术

    据广泛报道 Java 8 具有对无符号整数的库支持 然而 似乎没有文章解释如何使用它以及有多少可能 有些函数 例如 Integer CompareUnsigned 很容易找到 并且似乎可以实现人们所期望的功能 但是 我什至无法编写一个简单的
  • CXF Swagger2功能添加安全定义

    我想使用 org apache cxf jaxrs swagger Swagger2Feature 将安全定义添加到我的其余服务中 但是我看不到任何相关方法或任何有关如何执行此操作的资源 下面是我想使用 swagger2feature 生成
  • 在浏览器中点击应用程序时播放框架挂起

    我正在 Play 中运行一个应用程序activator run 也许 5 次中有 3 次 它会挂起 当我去http localhost 9000 它就永远坐在那里旋转 我看到很多promise timed out错误也 我应该去哪里寻找这个
  • java.io.IOException: %1 不是有效的 Win32 应用程序

    我正在尝试对 XML 文档进行数字签名 为此我有两个选择 有一个由爱沙尼亚认证中心为程序员创建的库 还有一个由银行制作的运行 Java 代码的脚本 如果使用官方 认证中心 库 那么一切都会像魅力一样进行一些调整 但是当涉及到银行脚本时 它会
  • 使用 ANTLR 为 java 源代码生成抽象语法树

    如何使用 ANTLR 从 java src 代码生成 AST 有什么帮助吗 好的 步骤如下 前往ANTLR站点 http www antlr org 并下载最新版本 下载Java g和JavaTreeParser g文件来自here htt
  • 如何为 Gson 编写自定义 JSON 反序列化器?

    我有一个 Java 类 用户 public class User int id String name Timestamp updateDate 我收到一个包含来自 Web 服务的用户对象的 JSON 列表 id 1 name Jonas
  • 当分配给变量时,我可以以某种方式重用 Gremlin GraphTraversals 代码吗?

    我有看起来像这样的 GraphTraversals attrGroup GraphTraversal
  • jdbc4.MySQLSyntaxErrorException:数据库中不存在表

    我正在使用 SpringBoot 开发一个网络应用程序 这是我的application properties文件来指定访问数据库的凭据 spring datasource driverClassName com mysql jdbc Dri
  • Microsoft Graph 身份验证 - 委派权限

    我可以使用 Microsoft Graph 访问资源无需用户即可访问 https developer microsoft com en us graph docs concepts auth v2 service 但是 此方法不允许我访问需
  • Clip 在 Java 中播放 WAV 文件时出现严重延迟

    我编写了一段代码来读取 WAV 文件 大小约为 80 mb 并播放该文件 问题是声音播放效果很差 极度滞后 你能告诉我有什么问题吗 这是我的代码 我称之为doPlayJframe 构造函数内的函数 private void doPlay f
  • Spring Data 与 Spring Data JPA 与 JdbcTemplate

    我有信心Spring Data and Spring Data JPA指的是相同的 但后来我在 youtube 上观看了一个关于他正在使用JdbcTemplate在那篇教程中 所以我在那里感到困惑 我想澄清一下两者之间有什么区别Spring
  • Windows 上的 Nifi 命令

    在我当前的项目中 我一直在Windows操作系统上使用apache nifi 我已经提取了nifi 0 7 0 bin zip文件输入C 现在 当我跑步时 bin run nifi bat as 管理员我在命令行上看到以下消息 但无法运行
  • android Accessibility-service 突然停止触发事件

    我有一个 AccessibilityService 工作正常 但由于开发过程中的某些原因它停止工作 我似乎找不到这个原因 请看一下我的代码并告诉我为什么它不起作用 public class MyServicee extends Access
  • KeyPressed 和 KeyTyped 混淆[重复]

    这个问题在这里已经有答案了 我搜索过之间的区别KeyPressedand KeyTyped事件 但我仍然不清楚 我发现的一件事是 Keypressed 比 KeyTyped 首先被触发 请澄清一下这些事件何时被准确触发 哪个适合用于哪个目的
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp
  • java8 Collectors.toMap() 限制?

    我正在尝试使用java8Collectors toMap on a Stream of ZipEntry 这可能不是最好的想法 因为在处理过程中可能会发生异常 但我想这应该是可能的 我现在收到一个我不明白的编译错误 我猜是类型推理引擎 这是

随机推荐

  • [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 分析 每次都分成两半处理子问题