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即可!

快速排序

快速排序,名字听起来就很快!

那么,这么快的排序是怎么实现的呢?我们这里以升序为例(降序的话找数的逻辑相反),把它拆解成以下几步:

  1. 选定一个基准值,这里我们一般选取第一个数为基准值

  2. 设定双指针,也就是书里面说的哨兵。

    2.1 一个哨兵从右往左走找比 基准值小(大) 的数,一个哨兵从左往右找比 基准值大(小) 的数,找到了就交换两个数。

    2.2 等到两个哨兵相遇就交换基准值和哨兵

    这样数组的左边都是比 基准值小(大) 的数,右边都是比 基准值大(小) 的数。

  3. 左边界基准值位置-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;}
}

演示

运行代码,控制台输入可得:

在这里插入图片描述

课后习题

在前两期博客中:

  1. Java玩转《啊哈算法》排序之桶排序

  2. Java玩转《啊哈算法》排序之冒泡排序

我都给出了力扣上面的同一道题,作为课后习题:

912. 排序数组

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

在这里插入图片描述
如果用冒泡排序,那就更尴尬了,直接超时,通过都通过不了:

在这里插入图片描述

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

噔噔蹬蹬:

在这里插入图片描述

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

在这里插入图片描述

这也正印证了上文所说的,快速排序的执行速率不稳定,最差的时候跟冒泡排序是一样的。

虽然桶排序算法跟贪心算法一样因为思路都比较简单,所以容易被人轻视。

俗话说,真心(简单)往往留不住,唯有套路(复杂)得人心。

但是桶排序在这道题上面是当之无愧的老大哥!!!

在这里插入图片描述

看来没有最牛逼的算法,只有最合适的算法

当然,快速排序针对多重复元素进行 三路快排 的话, 虽然速率还是比不上桶排序,但是也能通过这道题。

不过这个超纲了,不在本篇博客的讨论范围内了,感兴趣的同学可以去看一下这位朋友的题解:

快速排序优化(针对多重复元素情况)

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

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

相关文章

安全耐用 一路稳行 极固轮胎3大系列产品重磅上市

临近年关&#xff0c;全国范围内雨雪天气多发&#xff0c;让极端天气环境下的行车安全再次成为热议话题。路面寒冷湿滑&#xff0c;交通事故频发&#xff0c;也让大家开始关注一个话题&#xff1a;如何确保汽车在湿滑路面上的安全系数&#xff1f;或者说&#xff0c;如果遭遇类…

如何让wordpress首页只显示某一篇文章全部内容?在您的主页显示选择

大多数WordPress站点首页默认都是显示最新发布的文章列表&#xff0c;不过有些站点比较特殊&#xff0c;只想显示某一篇文章的全部内容&#xff0c;那么应该怎么设置呢&#xff1f; 其实&#xff0c;WordPress后台 >> 设置 >> 阅读 >> 在“您的主页显示”中…

基于flask的个人博客项目从0到1

项目展示 首页 文章时间线页面 笔记页面 留言页面 关于页面 后台页面-文章管理 后台页面-笔记页面 后台页面-分类 后台管理-新增标签 后台管理-标签页面 后台管理-新增标签 后台管理-关于页面 2.项目详述 该博客开源地址点击跳转&#xff0c;该项目已部署上线&#xff0c;…

《HTML 简易速速上手小册》第8章:HTML 表单高级技术(2024 最新版)

文章目录 8.1 数据收集与处理8.1.1 基础知识8.1.2 案例 1&#xff1a;创建一个注册表单8.1.3 案例 2&#xff1a;创建一个调查问卷表单8.1.4 案例 3&#xff1a;创建一个动态添加输入字段的表单 8.2 定制化表单元素8.2.1 基础知识8.2.2 案例 1&#xff1a;创建一个带有定制选择…

【GAMES101】Lecture 12 阴影 Shadow Mapping

这里是光栅化的最后一部分&#xff0c;讲这个光栅化里面怎么实现这个阴影 实际上阴影就是光源看不到的地方但是是我们能看到的地方&#xff0c;那这个地方就应该有阴影&#xff0c;那具体怎么做呢&#xff0c;这个就叫做Shadow Mapping&#xff0c;分两步做 我们之前说过这个解…

Stable Diffusion系列(四):提示词规则与使用

文章目录 基础规则高级规则插件使用基于相机镜头增强提示词常用提示词总结奇特提示词珍藏 基础规则 所谓提示词&#xff0c;也就是文生图中的文&#xff0c;由连贯的英语单词或句子组成。其最基础的规则是&#xff1a; 不同提示词之间需要用英文逗号分隔&#xff0c;空格和换…

基于大数据的B站数据分析系统的设计与实现

摘要&#xff1a;随着B站&#xff08;哔哩哔哩网&#xff09;在国内视频分享平台的崛起&#xff0c;用户规模和数据量不断增加。为了更好地理解和利用这些海量的B站数据&#xff0c;设计并实现了一套基于Python的B站数据分析系统。该系统采用了layui作为前端框架、Flask作为后端…

mfc140.dll找不到了要怎么解决?教你多种修复mfc140.dll的方法

遭遇 mfc140.dll 文件缺失的状况时&#xff0c;首要任务是保持冷静&#xff0c;并深入理解问题所在&#xff0c;随后按照科学的方法来应对这一挑战。本篇文章概述了多种应对策略&#xff0c;从适合新手的基本步骤到针对有技术基础用户的高级方案&#xff0c;各种手段都能有效地…

linux系统查看占用cpu程序

目录 一&#xff1a;top 二&#xff1a; ps 三&#xff1a;perf 四&#xff1a;/proc/stat 五&#xff1a;pidstat 一&#xff1a;top 使用 top 命令&#xff1a;在终端中输入 top 命令&#xff0c;系统会显示当前正在运行的进程和它们的资源占用情况。默认情况下&#…

awk 文本处理工具三剑客

一、什么是awk 1.1 awk 基本概念 awk&#xff08;语言&#xff09;&#xff1a; 读取一行处理一行 是一个功能强大的编辑工具&#xff0c;逐行读取输入文本&#xff0c;默认以空格或tab键作为分隔符作为分隔&#xff0c;并按模式或者条件执行编辑命令。而awk比较倾向于将一行…

【网络】:网络套接字(UDP)

网络套接字 一.网络字节序二.端口号三.socket1.常见的API2.封装UdpSocket 四.地址转换函数 网络通信的本质就是进程间通信。 一.网络字节序 我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网…

UE5.1_常用节点说明(经常忘记怎么用?)(常改)

UE5.1_常用节点说明&#xff08;经常忘记怎么用&#xff1f;&#xff09;&#xff08;常改&#xff09; 1. Gate——门节点。只有当门是Open状态才会执行Exit后面的代码。 Open开门&#xff1b;Close关门&#xff1b;Toggle开门和关门交替。 2. 关于控制ArmLength即控制相机前…

vite+vue3+ts项目上线docker 配置反向代理API

这次重点的坑是反向代理。 1。项目中配置代理&#xff0c;为了跨域请求数据 项目根目录中新建vite.config.ts文件 在文件中添加配置代理 注意&#xff1a;其中 /api 和target 的地址后面没有 / 2。在项目根目录中新建Httprequest.ts文件&#xff0c;引入axios&#xff0c;并…

Kotlin快速入门系列8

Kotlin的泛型 与Java一样&#xff0c;Kotlin也提供泛型。泛型&#xff0c;即 "参数化类型"&#xff0c;将类型参数化&#xff0c;可以用在类&#xff0c;接口&#xff0c;方法上。可以为类型安全提供保证&#xff0c;消除类型强转的烦恼。声明泛型类的格式如下&…

UDP/TCP协议特点

1.前置知识 定义应用层协议 1.确定客户端和服务端要传递哪些信息 2.约定传输格式 网络上传输的一般是二进制数据/字符串 结构化数据转二进制/字符串 称为序列化 反之称之为反序列化 下面就是传输层了 在TCP/IP协议中,我们以 目的端口,目的IP 源端口 源IP 协议号这样一个五…

202413读书笔记|《好好恋爱是件正经事》——希望我们的故事永远崭新得像刚刚开始,永远未完待续

202413读书笔记|《好好恋爱是件正经事》——希望我们的故事永远崭新得像刚刚开始&#xff0c;永远未完待续 明亮的色彩&#xff0c;小红和小绿&#xff0c;哲理又日常治愈的文字&#xff0c;明快的线条&#xff0c;丰富的背景色&#xff0c;星星点点的⭐️斑斓点缀。 是情侣的…

能替代微软AD的国产化方案,搭建自主可控的身份管理体系

随着国产化替代步伐加速&#xff0c;以及企业出于信息安全建设的需要&#xff0c;越来越多的企业和组织开始考虑将现有的微软 Active Directory&#xff08;AD&#xff09;替换为国产化的LDAP身份目录服务&#xff08;也称统一身份认证和管理&#xff09;系统。本文将介绍一种国…

世界坐标系转换为平面地图坐标

将世界坐标系转换为平面地图坐标的方法通常涉及地图投影。地图投影是一种将地球(一个三维球体)上的点转换为平面(二维)地图上的点的方法。 这里介绍几种常见的地图投影方法: 墨卡托投影(Mercator Projection): 这是最常见的投影方式之一,尤其用于航海地图。它将经纬度…

2023年春秋杯网络安全联赛冬季赛_做题记录

可信计算 基于挑战码的双向认证1 可信计算赛题-双向认证挑战模式.docx 使用命令进行SSH登录上去 ssh player8.147.131.156 -p 18341 # 记得加上-p参数指定端口&#xff0c;不然默认的是22端口看见word文档的提示&#xff0c;先尝试一下 直接获得了flag1 web 魔术方…

24小时涨粉10w+的AI小游戏-哄哄模拟器

近年来&#xff0c;随着chatGPT的爆火&#xff0c;一系列的AI应用应运而生。比如&#xff1a;AI绘画&#xff0c;AI写作等。今天我们来看看最近很火的一个AI小游戏-哄哄模拟器。 1. 试玩体验 这款游戏名叫“哄哄模拟器”&#xff0c;体验地址为&#xff1a;https://hong.grea…