Java玩转《啊哈算法》排序之快速排序
地图
- 引子
- 代码地址
- 快速排序
- 核心代码
- 优劣
- 完整代码
- 演示
- 课后习题
引子
搭嘎好!本人最近看的《啊哈算法》这本书写的确实不错,生动形象,在保持算法讲解准确性的同时又不失趣味性。
但对我来说,稍显遗憾的是,书籍代码是c语言,而不是本人常用的Java。
那就弥补遗憾,说干就干,把这本书的示例语言用java给翻译一遍!!!
于是就有了本篇博客,这是第三篇博客,主要讲解快速排序。

来不及买纸质书但又想尽快感受算法魅力的童鞋也甭担心,电子版的下载链接已经放到下方了,可尽情下载。
链接:https://pan.baidu.com/s/1imxiElcCorw2F-HJEnB-PA?pwd=jmgs
提取码:jmgs
代码地址
本文代码已开源:
git clone https://gitee.com/guqueyue/my-blog-demo.git
请切换到gitee分支,
然后查看aHaAlgorithm模块下的src/main/java/com/guqueyue/aHaAlgorithm/chapter_1_Sort即可!
快速排序
快速排序,名字听起来就很快!
那么,这么快的排序是怎么实现的呢?我们这里以升序为例(降序的话找数的逻辑相反),把它拆解成以下几步:
-
选定一个基准值,这里我们一般选取第一个数为基准值
-
设定双指针,也就是书里面说的哨兵。
2.1 一个哨兵从
右往左走找比 基准值小(大) 的数,一个哨兵从左往右找比 基准值大(小) 的数,找到了就交换两个数。2.2 等到两个哨兵相遇就交换基准值和哨兵
这样数组的左边都是比 基准值小(大) 的数,右边都是比 基准值大(小) 的数。
-
以
左边界和基准值位置-1为一个数组,右边界和基准值位置+1为一个数组,再进行如上操作。
一直到左右边界相遇,则排序完成。

当然,这里面采用了递归的编程技巧,实现了分而治之的编程思想,才能达到我们想要的目的。
关于这个,我当初写的关于《算法图解》第三章<递归>、第四章<快速排序>里面也有相应的介绍:
肝了几万字,送给看了《算法图解》却是主攻Java的你和我(上篇)
相比于《算法图解》那本书,这本书讲快速排序明显要更加清晰直观。
下面是快速排序整体的流程图:

还没懂?列一个快速排序第一次交换的动图,是不是清晰很多了呢?

如果还是不是很明白,就去看书吧,里面有详细的图文步骤,我这里就不多加赘述啦。
核心代码
话已经说了很多了,直接上代码:
/*** @Description 快速排序* @Param [arr: 数组, left: 左边界, right: 右边界]* @return void**/private static void quickSort(int[] arr, int left, int right) {if (left > right) { // 左边不能大于右边return;}int temp = arr[left]; // 基准值int i = left, j = right;while (i < j) {// 找到比基准值更小的数,右边先找(为啥一定要右边先找? - 1 3 2) 防止基准值是最小的数,左边先走,就会把基准值交换掉while (arr[j] >= temp && i < j) {j--;}// 找到比基准值更大的数,这边必须设置等于temp,不然左边的数不会走while (arr[i] <= temp && i < j) {i++;}// 如果没有相遇,则: i == j 时,没必要交换if (i < j) {int t = arr[i];arr[i] = arr[j];arr[j] = t;}}// 基准值归位arr[left] = arr[j];arr[j] = temp;// 这里 i,j 是相等的quickSort(arr, left, j-1); // 左半边继续排序quickSort(arr, j+1, right); // 右半边继续排序}
优劣
- 空间复杂度为
O(N),属于 原地排序算法 了,即不占用额外的空间。 - 平均时间复杂度为
O(NlogN), 但是有些情况下时间复杂度最高可达O(N^2),不过问题不大,最坏的情况也就和冒泡排序一样不是?
上面说到快速排序有最坏的情况时间复杂度为O(N^2),你能想到是哪种情况吗?
想不到的话也没关系,下文有提示。
完整代码
诺:
package com.guqueyue.aHaAlgorithm.chapter_1_Sort;import java.util.Arrays;
import java.util.Scanner;/*** @Author: guqueyue* @Description: 快速排序* @Date: 2024/1/10**/
public class QuickSort {public static void main(String[] args) {// 获取整数数组int[] arr = getArr();System.out.println("输入的数组为:" + Arrays.toString(arr));// 快速排序quickSort(arr, 0, arr.length - 1);System.out.println("排序后的数组为:" + Arrays.toString(arr));}/*** @Description 快速排序* @Param [arr: 数组, left: 左边界, right: 右边界]* @return void**/private static void quickSort(int[] arr, int left, int right) {if (left > right) { // 左边不能大于右边return;}int temp = arr[left]; // 基准值int i = left, j = right;while (i < j) {// 找到比基准值更小的数,右边先找(为啥一定要右边先找? - 1 3 2) 防止基准值是最小的数,左边先走,就会把基准值交换掉while (arr[j] >= temp && i < j) {j--;}// 找到比基准值更大的数,这边必须设置等于temp,不然左边的数不会走while (arr[i] <= temp && i < j) {i++;}// 如果没有相遇,则: i == j 时,没必要交换if (i < j) {int t = arr[i];arr[i] = arr[j];arr[j] = t;}}// 基准值归位arr[left] = arr[j];arr[j] = temp;// 这里 i,j 是相等的quickSort(arr, left, j-1); // 左半边继续排序quickSort(arr, j+1, right); // 右半边继续排序}/*** @Description 获取整数数组* @Param []* @return int[]**/private static int[] getArr() {Scanner scanner = new Scanner(System.in);System.out.print("请输入数字个数:");int n = scanner.nextInt();int[] arr = new int[n];System.out.printf("请输入%d个数, 中间用空格隔开,再回车:", n);for (int i = 0; i < n; i++) {arr[i] = scanner.nextInt();}return arr;}
}
演示
运行代码,控制台输入可得:

课后习题
在前两期博客中:
Java玩转《啊哈算法》排序之桶排序
Java玩转《啊哈算法》排序之冒泡排序
我都给出了力扣上面的同一道题,作为课后习题:
912. 排序数组

但是比较尴尬的是,用桶排序做这道题目,占用内存太多了,仅击败 34.93% 使用Java的用户!

如果用冒泡排序,那就更尴尬了,直接超时,通过都通过不了:

但是如果你学会了本文中的快速排序,能不能做到,又快又稳(占用内存少) 呢?
噔噔蹬蹬:

很遗憾,翻车了,又超时了,我们翻开超时的测试用例可以发现,有非常多的重复元素:

这也正印证了上文所说的,快速排序的执行速率不稳定,最差的时候跟冒泡排序是一样的。
虽然桶排序算法跟贪心算法一样因为思路都比较简单,所以容易被人轻视。
俗话说,真心(简单)往往留不住,唯有套路(复杂)得人心。
但是桶排序在这道题上面是当之无愧的老大哥!!!

看来没有最牛逼的算法,只有最合适的算法。
当然,快速排序针对多重复元素进行 三路快排 的话, 虽然速率还是比不上桶排序,但是也能通过这道题。
不过这个超纲了,不在本篇博客的讨论范围内了,感兴趣的同学可以去看一下这位朋友的题解:
快速排序优化(针对多重复元素情况)
相关文章:
Java玩转《啊哈算法》排序之快速排序
心无挂碍,无挂碍故,无有恐怖,远离颠倒梦想,究竟涅槃。 地图 引子代码地址快速排序核心代码优劣完整代码演示 课后习题 引子 搭嘎好!本人最近看的《啊哈算法》这本书写的确实不错,生动形象,在保…...
静态代理IP该如何助力Facebook多账号注册运营?
在Facebook运营中,充分利用静态代理IP是多账号运营的关键一环。通过合理运用静态代理IP,不仅可以提高账号安全性,还能有效应对Facebook的算法和限制。以下是这些关键点,可以帮助你了解如何运用静态代理IP进行Facebook多账号运营&a…...
npm 淘宝镜像正式到期
由于node安装插件是从国外服务器下载,如果没有“特殊手法”,就可能会遇到下载速度慢、或其它异常问题。 所以如果npm的服务器在中国就好了,于是我们乐于分享的淘宝团队干了这事。你可以用此只读的淘宝服务代替官方版本,且同步频率…...
【Spring Boot 3】【@Scheduled】多线程执行定时任务
【Spring Boot 3】【@Scheduled】多线程执行定时任务 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新…...
TypeScript 基础学习
TypeScript是具有类型语法的JavaScript。 是JavaScript超集,可以编译为纯JavaScript,构建安全可靠的代码,进行类似 babel 的转换。 一种基于JavaScript的强类型、静态的编程语言,提供了类型检测的工具。 特性: 易读…...
《CSS3》田字网格背景(外实线内虚线)的实现
一、前言 记录一些有趣的CSS实现方式,总所周知,当一段效果可以通过CSS实现的时候,绝不使用Javascript来实现,因此记录一些有意思的CSS效果,一来是方便自己学习,另一来是方便以后在需要使用到的时候能快速找…...
图书管理系统(ArrayList和LinkedList)--versions3.0
目录 一、项目要求: 二、项目环境 三、项目使用的知识点 四、项目代码 五、项目运行结果 六、项目难点分析 图书管理系统--versions1.0: 图书管理系统--versions1.0-CSDN博客文章浏览阅读981次,点赞29次,收藏17次。本文使用…...
游戏开发丨基于Pygame的AI版贪吃蛇小游戏
文章目录 写在前面需求分析程序设计程序分析运行结果系列文章写在后面 写在前面 本期内容 基于pygame的AI版贪吃蛇小游戏 所需环境 pythonpycharm或anacondapygame 下载地址 https://download.csdn.net/download/m0_68111267/88789665 需求分析 本游戏使用Pygame模块开…...
qt-C++笔记之QStringList、QList<QString>、QString、QChar、QList<QChar>区别
qt-C笔记之QStringList、QList、QString、QChar、QList区别 —— 杭州 2024-01-30 凌晨0:27 参考博文:qt-C笔记之QStringList code review! 文章目录 qt-C笔记之QStringList、QList<QString>、QString、QChar、QList<QChar>区别1.Qt的字符容器类1.QSt…...
python爬虫学习之解析_BeautifulSoup
目录 一、bs4的基本使用 (1)导入 (2)创建对象 二、节点定位 1、根据标签名查找节点 2、基本函数使用 (1)find (2)find_all (3)select 三、节点信息 1、获取节…...
2024美赛数学建模赛题解读常用模型算法
回归拟合预测 拟合预测是建立一个模型去逼近实际数据序列的过程,适用于发展性的体系。建立模型时,通常都要指定一个有明确意义的时间原点和时间单位。而且,当t趋向于无穷大时,模型应当仍然有意义。将拟合预测单独作为一类体系研究…...
NoSQL 数据库管理系统和模型的比较
前些天发现了一个人工智能学习网站,通俗易懂,风趣幽默,最重要的屌图甚多,忍不住分享一下给大家。点击跳转到网站。 NoSQL 数据库管理系统和模型的比较 介绍 当大多数人想到数据库时,他们通常会想到传统的关系数据库…...
数据库(SQL)
目录 1 触发器 1.1 触发器简介 1.2 触发器的创建 语法 说明 1.3 示例 2 存储过程 2.1 什么是存储过程(函数) 2.1.1 存储过程和存储函数的区别 2.2 优势 2.3 应用场景 2.4 存储过程的创建和使用 说明 各参数类型所实现的存储过程 无参数无返…...
如何用Docker+jenkins 运行 python 自动化?
1.在 Linux 服务器安装 docker 2.创建 jenkins 容器 3.根据自动化项目依赖包构建 python 镜像(构建自动化 python 环境) 4.运行新的 python 容器,执行 jenkins 从仓库中拉下来的自动化项目 5.执行完成之后删除容器 前言 环境准备 Linux 服务器一台(我的是 CentOS7)…...
uniapp瀑布流实现
1. 图片瀑布流: 不依赖任何插件,复制即可见效: <template><view class"page"><view class"left" ref"left"><image class"image" v-for"(item,i) in leftList" :k…...
鸿蒙:@Link装饰器-父子双向同步
子组件中被Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。从API version 9开始,该装饰器支持在ArkTS卡片中使用。 需要注意:Link装饰的变量与其父组件中的数据源共享相同的值。Link装饰器不能在Entry装饰的自定义组件中使用。 一、装饰器使…...
Leetcode--27
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面…...
使用Eclipse搞Android项目报错
相信现在都没什么人还会用Eclipse来开发的了。 不过安装完后,打开Eclipse会提示我的Jdk版本不符合 --------------------------- Incompatible JVM --------------------------- Version 1.8.0_391 of the JVM is not suitable for this product. Version: 17 or g…...
import sys是什么
import sys语句 允许你使用sys模块提供的各种功能,从而更好地与Python解释器和操作系统底层进行交互。通过熟练掌握sys模块的使用,可以大大提高Python开发的效率和灵活性。 sys模块 是Python的内置模块之一,用于与Python解释器和系统环境交…...
Python爬虫:XPath基本语法
XPath(XML Path Language)是一种用于在XML文档中定位元素的语言。它使用路径表达式来选择节点或节点集,类似于文件系统中的路径表达式。 不啰嗦,讲究使用,直接上案例。 导入 pip3 install lxmlfrom lxml import etr…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
