74-快速排序——一路快排

news2024/11/17 13:48:19

快速排序是影响二十世纪最伟大的排序算法之一。

JDK的双轴快速排序就是对快排的优化,本质还是快排。

  1. 从待排序区间选择一个数,作为基准值/分区点(pivot),此时默认选择数组的第一个元素作为比较的基准值。
  2. partition:遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等)放到基准值的右边。即选取一个分区点,将数组分成三部分:基准值之前的数组<基准值<基准值之后的数组。
  3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度==1,代表已经有序,或者小区间长度==0,代表没有数据。

/**
 * 快速排序 一路快排
 * @param arr
 */
public static void quickSort(int[] arr) {
    quickSortInternal(arr, 0, arr.length - 1);
}

/**
 * 在l...r上进行快速排序
 * @param arr
 * @param l
 * @param r
 */
private static void quickSortInternal(int[] arr, int l, int r) {
    //递归终止时,小数组使用插入排序
    if(r - l <= 15) {
        insertBase(arr, l ,r);
        return;
    }
    //选择基准值,找到该值对应的下标
    int p = partition(arr, l, r);
    //在<基准值区间进行快速排序
    quickSortInternal(arr, l, p - 1);
    //在>=基准值区间进行快速排序
    quickSortInternal(arr, p + 1, r);
}

/**
 * 在arr[l...r]上选择基准值,将数组划分为 <v 和 >= v 两部分,返回基准值对应的元素下标
 * @param arr
 * @param l
 * @param r
 * @return
 */
private static int partition(int[] arr, int l, int r) {
    //默认选择数组的第一个元素作为基准值
    int v = arr[l];

    //arr[l + 1...j] < v
    int j = l;
    //i是当前处理的元素下标
    //arr[l + 1...j] < v 最开始为空区间 [l + 1...l] = 0
    //arr[j + 1...i] >= v 最开始为空区间 [l + 1...l + 1] = 0
    for (int i = l + 1; i <= r; i++) {
         if(arr[i] < v) {
             swap(arr, j + 1, i);
             //小于v的元素值新增一个
             j++;
         }
    }
    //此时j下标对应的就是最后一个 < v 的元素,交换j和l的值,选取的基准值交换到j的位置
    swap(arr, l, j);
    return j;
}

代码在电脑上若出现问题,可能是栈溢出,解决:设置当前栈的大小为1M大小(用于50w数据)。

Environment Variables:-Xss = 1M

稳定性:不稳定。

分区时,当扫描arr[i] < v时,交换了arr[j] 和arr[i],对于arr[j + 1] >= v,就有可能把一个 = v从前面交换到了后面,分区函数无法保证稳定性。

时间复杂度:O(nlogn)递归过程中调用分区函数。

  • 分区函数的时间复杂度是O(n)
  • 递归过程就是不断将原数组根据基准值拆分为子数组,有点类似归并拆分。递归次数就是递归树的高度,时间复杂度是O(logn)

①当待排序元素接近有序时,递归树会退化为单支树(链表),快速排序的性能衰减为O(n ^ 2)。

解决->随机化快排:在数组中随机选取一个元素作为基准值,平衡左右两个子树的元素个数。

private static final ThreadLocalRandom random = ThreadLocalRandom.current();

 /**
  * 快速排序 一路快排
  * @param arr
  */
public static void quickSort(int[] arr) {
    quickSortInternal(arr, 0, arr.length - 1);
}

/**
 * 在l...r上进行快速排序
 * @param arr
 * @param l
 * @param r
 */
private static void quickSortInternal(int[] arr, int l, int r) {
    //递归终止时,小数组使用插入排序
    if(r - l <= 15) {
        insertBase(arr, l ,r);
        return;
    }
    //选择基准值,找到该值对应的下标
    int p = partition(arr, l, r);
    //在<基准值区间进行快速排序
    quickSortInternal(arr, l, p - 1);
    //在>=基准值区间进行快速排序
    quickSortInternal(arr, p + 1, r);
}

/**
 * 在arr[l...r]上选择基准值,将数组划分为 <v 和 >= v 两部分,返回基准值对应的元素下标
 * @param arr
 * @param l
 * @param r
 * @return
 */
private static int partition(int[] arr, int l, int r) {
    //优化:随机选择一个元素值作为基准值(在当前数组中)
    int randomIndex = random.nextInt(l, r);
    swap(arr, l, randomIndex);
    int v = arr[l];

    //arr[l + 1...j] < v
    int j = l;
    //i是当前处理的元素下标
    //arr[l + 1...j] < v 最开始为空区间 [l + 1...l] = 0
    //arr[j + 1...i] >= v 最开始为空区间 [l + 1...l + 1] = 0
    for (int i = l + 1; i <= r; i++) {
         if(arr[i] < v) {
             swap(arr, j + 1, i);
             //小于v的元素值新增一个
             j++;
         }
    }
    //此时j下标对应的就是最后一个 < v 的元素,交换j和l的值,选取的基准值交换到j的位置
    swap(arr, l, j);
    return j;
}

②当集合中包含大量重复元素时,最坏的情况是:集合中全是相等的元素。按照我们的分区,一个分区没有元素,一个分区元素为n,快排性能再次衰减为O(n ^ 2)。

导致蓝色区域元素个数远远大于橙色区域的元素个数,造成递归树的严重倾斜。

解决->二路快排/三路快排:将相等的元素均匀分布在左右两个子区间,保证递归树的平衡性。

 

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

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

相关文章

【 SpringBoot 配置⽂件 】

文章目录一、配置⽂件作⽤二、配置文件格式2.1 特殊说明2.2 为配置⽂件安装提示插件三、properties 配置⽂件说明3.1 properties 基本语法3.2 读取配置⽂件3.3 解决 properties 中文乱码3.4 properties 缺点分析四、yml 配置⽂件说明4.1 yml 基本语法4.2 yml 配置读取4.3 yml 使…

前后端分离——SpringBoot+Vue——3天速成企业级项目

前后端分离——SpringBootVue使用到的技术&#xff1a;vue3&#xff08;区别vue2&#xff09;前言vue2 vs vue3双向绑定更新实例化生命周期获取props数据和方法的定义watchEffect那么什么是 watchEffect &#xff1f;组件通信注意attrs和listeners路由vue3路由写法&#xff1a;…

ROS学习——艰辛的环境安装之路一VMware

文章目录VMware 安装下载安装VMware 安装 一些没用的介绍&#xff1a; VMware Workstation中文版是一个“虚拟 PC”软件。它使你可以在一台机器上同时运行二个或更多 Windows、DOS、LINUX 系统。与“多启动”系统相比&#xff0c;VMWare 采用了完全不同的概念。多启动系统在一…

《Web前端应用开发》考试试卷(模拟题)

一、产品搜索页面 打开“考试文件夹”中的input.html&#xff0c;完成以下步骤&#xff1a; 注意&#xff1a;本题仅能在input.html的&#xff08;1&#xff09;为产品名称所在的div添加样式属性&#xff0c;使得产品名称保持在文本框的左边&#xff1b; &#xff08;2&#xf…

PPT NO.1【用ppt如何做一张海报+字体】

PPT做得好的人&#xff0c;一定是站在观众的角度思考的人。 1、设置幻灯片尺寸大小&#xff1a; 设置完成后如下&#xff1a; 2、加载一张自己喜欢的图片进来&#xff1a;【图片越高清越好】 将图片铺满空白的地方&#xff0c;调整好自己喜欢的区域&#xff1a; 做裁剪&#xf…

数据结构修炼第一篇:时间复杂度和空间复杂度

系列文章目录 第一章 时间复杂度和空间复杂度 第二章 顺序表&#xff0c;列表 第三章 栈和队列 第四章 二叉树 第五章 排序 目录 系列文章目录 &#x1f3c6;文章目录 &#x1f3c6;前言 &#x1f3c6;一、算法的复杂度 &#x1f3c6;二、时间复杂度的概念 大0渐进 作…

【Go语言从入门到精通系列-基础篇】Go安装 + 语言特性,以及开启你人生中的第一个go程序

系列文章 【Go语言从入门到精通系列-基础篇】Go安装 语言特性&#xff0c;以及开启你人生中的第一个go程序 【Go语言从入门到精通系列-基础篇】Go语言包的管理以及基础语法与使用。 Go语言从入门到精通系列-基础篇系列文章前言第一章 Go语言开发基础1.1 Go语言的优势1.2 Go语…

C语言快速排序非递归实现

目录 栈的辅助&#xff08;栈的实现可以调用之前实现的数据结构&#xff09;&#xff1a; 1&#xff0c;初始状态 2&#xff0c;循环 3&#xff0c;终止 4&#xff0c;注意 小点&#xff1a; 1&#xff0c;递归的使用会造成栈空间的消耗&#xff0c;使用递归&#xff0c;…

刷题day51:重新安排行程 ***

题意描述&#xff1a; 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发的先生&#xff0c;所以该行程必须从 …

【宝塔邮局管理器】使用教程、Email配置

1.安装宝塔邮局插件前&#xff0c;需要先安装redis服务&#xff0c;并设置redis密码。 安装完Redis服务后设置密码&#xff0c;设置密码时不要使用&%这类特殊符号 会导致负载状态显示异常&#xff0c;可使用英文数字组合密码 PS&#xff1a;邮局的反垃圾模块 rspamd服务需要…

Spring Cloud快速入门

文章目录Spring Cloud快速入门一、基础概念1、微服务架构2、微服务技术栈3、什么是Spring Cloud?4、Spring Cloud和Spring Boot的联系&#xff1f;5、比较成熟的互联网架构二、Rest环境搭建1、搭建提供者1.1、创建一个父工程1.2、创建一个springcloud-api模块1.3、创建一个spr…

SSM学习记录3:响应(注释方式 + SprigMVC项目 + 2022发布版本IDEA)

响应 ResponseBody注解的作用是将当前控制器中方法的返回值作为响应体 1.返回页面 无需在方法上进行ResponseBody注解&#xff0c;只需RequestMapping匹配地址&#xff0c;并且返回值为带后缀的页面名字符串 前面学习中除了json数据&#xff0c;所有带ResponseBody注解的方法…

iphone用什么蓝牙耳机好?和iphone适配的蓝牙耳机推荐

随着科技的不断发展&#xff0c;人们已经离不开各种智能设备。蓝牙耳机作为一种非常方便的音频设备&#xff0c;已经逐渐成为了许多人日常生活中不可或缺的一部分。然而&#xff0c;苹果产品的价格一直都是昂贵的&#xff0c;有没有与iphone适配的耳机呢&#xff1f;下面我们来…

ServletAPI详解(三)-HttpServletRequest

我们来看第二个类:HttpServletRequest HttpServletRequest HttpServletRequest表示的是一个http请求对象,是tomcat自动构造的,tomcat会实现监听端口,接收连接,读取请求,解析请求,构造请求对象等一系列操作 下面的方法可用在 Servlet 程序中读取 HTTP 头。这些方法通过 HttpS…

若依— — 快速入门【源码分析】

若依— — 快速入门 1 什么是若依 官网地址&#xff1a;http://www.ruoyi.vip/ 若依是一款优秀的开源项目&#xff0c;涉及到企业开发中大部分的管理系统&#xff0c;我们依此为模板进行二次开发&#xff0c;可以快速开发出符合大部分公司中的后台管理系统。 2 使用若依 使用开…

Spring Security --- authorizeRequests配置

目录 自定义配置类之访问权限 匹配顺序规则 访问控制包含 访问控制url匹配 访问控制方法 角色、权限判断 使用注解进行角色权限控制 自定义配置类之访问权限 http.authorizeRequests()主要是对url进行访问权限控制通过这个方法来实现url授权操作支持链式写法 匹配顺序…

【react全家桶学习】react简介

react是什么&#xff1f; react是用于构建用户界面的JS库&#xff0c;是一个将数据渲染为HTML视图的开源JS库 谁开发的&#xff1f; 由Facebook开发&#xff0c;且开源 为什么要学&#xff1f; 原生JavaScript操作DOM繁琐、效率低 ( DOM-API操作 UI)使用JavaScript直接操作…

Attention注意力机制

加粗样式通俗理解&#xff1a;你会注意什么&#xff1f; 对于一个模型而言&#xff08;CNN&#xff0c;LSTM&#xff09;&#xff0c;模型本身很难决定什么重要什么不重要&#xff0c;因此注意力机制诞生了。 注意力机制&#xff1a;我们会把焦点聚焦在比较重要的事务上 怎么…

详细聊一聊Android Apk的四代签名

简介 大部分开发者对apk签名还停留在APK v2&#xff0c;对APK v3和APK v4了解很少&#xff0c;而且网上大部分文章讲解的含糊不清&#xff0c;所以根据官网文档重新整理一份。 apk签名从APK v1到APK v2改动很大&#xff0c;是颠覆性的&#xff0c;而APK v3只是对APK v2的一次…

RocketMQ是是如何管理消费进度的?又是如何保证消息成功消费的?

RocketMQ消费者保障 作者: 博学谷狂野架构师GitHub&#xff1a;GitHub地址 &#xff08;有我精心准备的130本电子书PDF&#xff09; 只分享干货、不吹水&#xff0c;让我们一起加油&#xff01;&#x1f604; 消息确认机制 consumer的每个实例是靠队列分配来决定如何消费消息的…