AcWing算法基础课-785快速排序-Java题解

news2024/11/28 3:32:32

heweilai-bolg-title-image-of-the-article

大家好,我是何未来,本篇文章给大家讲解《AcWing算法基础课》785 题——快速排序。这篇文章介绍了使用快速排序算法对整数数列进行排序的方法,包括选择基准元素、分区操作和递归排序子数组。通过详细的步骤和示例,解释了快速排序的过程及其非稳定性特征,并提供了相应的 Java 代码实现。

文章目录

  • ❓题目描述
  • 💡算法思路
  • ✅Java代码
  • 🔗参考

❓题目描述

给定你一个长度为 n 的整数数列。

请你使用快速排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

输入格式

输入共两行,第一行包含整数 n。

第二行包含 n 个整数(所有整数均在 1∼10^9 范围内),表示整个数列。

输出格式

输出共一行,包含 n 个整数,表示排好序的数列。

数据范围

1≤n≤100000

输入样例:

5
3 1 2 4 5

输出样例:

1 2 3 4 5

💡算法思路

  1. 选择基准元素:从数组中选择一个元素作为基准。这里我们选择的是中间位置的元素。
  2. 分区操作:重新排列数组,将所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区操作。
  3. 递归排序子数组:递归地将小于基准值元素的子数列和大于基准值元素的子数列排序。

具体实现步骤如下:

  • 首先检查数组的起始索引l是否大于或等于结束索引r,如果是,则直接返回,因为这意味着数组已经是有序的或者是空数组。
  • 初始化两个指针ij,分别指向数组的起始位置的前一个位置和结束位置的后一个位置。选择数组的中间元素作为基准元素x
  • 使用两个指针ij从数组的两端向中间移动,直到i找到一个大于或等于基准的元素,j找到一个小于或等于基准的元素。如果i仍然小于j,则交换这两个元素。
  • 重复上述过程,直到i不再小于j
  • 递归地对基准元素左侧和右侧的子数组进行快速排序。

时间复杂度:O(n log n)
空间复杂度:O(n)
快速排序是非稳定排序:快速排序的分区过程中,当遇到与基准元素相等的元素时,通常会停止移动指针(在某些实现中,指针会继续移动),这可能导致相同元素的相对顺序被改变。例如,如果数组中有多个相同的元素,分区操作可能会将这些元素分散到基准的两侧,从而改变它们的相对顺序。

稳定排序的定义是:在排序过程中,具有相同键值的元素在排序前后的相对位置保持不变。然而,快速排序的分区操作可能会改变相同元素的相对顺序。

接下来,我给大家举个具体的例子来说明为什么快速排序是非稳定排序。

假设我们有一个包含学生信息的数组,每个学生由他们的姓名和成绩组成。我们希望按照成绩对学生进行排序。初始数组如下:

[ ("何未来", 85), ("乔布斯", 75), ("牛顿", 85), ("图灵", 75) ]

选择基准元素 ("牛顿", 85),进行第一次分区操作:

  1. 初始指针位置:i = -1j = 4
  2. 移动 i 直到找到大于或等于基准的元素:i 停在 ("何未来", 85)
  3. 移动 j 直到找到小于或等于基准的元素:j 停在 ("图灵", 75)
  4. 交换 ij 指向的元素:
[ ("图灵", 75), ("乔布斯", 75), ("牛顿", 85), ("何未来", 85) ]

第一次分区结束,基准元素 ("牛顿", 85) 的位置已经确定。现在我们有两个子数组:

  • 左子数组:[ ("图灵", 75), ("乔布斯", 75) ]
  • 右子数组:[ ("何未来", 85) ]

我们先对左子数组进行递归排序:

选择基准元素 ("乔布斯", 75),进行第二次分区操作:

  1. 初始指针位置:i = -1j = 2
  2. 移动 i 直到找到大于或等于基准的元素:i 停在 ("图灵", 75)
  3. 移动 j 直到找到小于或等于基准的元素:j 停在 ("乔布斯", 75)
  4. 交换 ij 指向的元素:
[ ("乔布斯", 75), ("图灵", 75) ]

第二次分区结束,基准元素 ("乔布斯", 75) 的位置已经确定。现在我们有两个子数组:

  • 左子数组:[ ](空数组)
  • 右子数组:[ ("图灵", 75) ]

由于左子数组为空,右子数组只有一个元素,这两个子数组都已经是有序的。

接下来对右子数组进行递归排序:

右子数组 [ ("何未来", 85) ] 只有一个元素,已经是有序的。

最终排序结果:

[ ("乔布斯", 75), ("图灵", 75), ("牛顿", 85), ("何未来", 85) ]

通过这个过程,我们可以看到,初始数组中相同成绩的学生 ("何未来", 85)("牛顿", 85) 的相对顺序在排序后发生了变化,从 ("何未来", 85) 在前变成了 ("牛顿", 85) 在前。这就是快速排序不稳定性的体现。

✅Java代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class Aw785 {

	// 创建一个StreamTokenizer用于读取输入
	static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

	// 读取下一个整数的方法
	static int nextInt() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}

	static int n; // 存储数组的大小
	static int[] nums = new int[100000 + 10]; // 存储输入的数组,预留一些额外的空间

	public static void main(String[] args) throws IOException {
		n = nextInt(); // 读取数组的大小
		for (int i = 0; i < n; i++) {
			nums[i] = nextInt(); // 读取数组的每个元素
		}
		quickSort(0, n - 1, nums); // 调用快速排序方法对数组进行排序
		for (int i = 0; i < n; i++) {
			System.out.print(nums[i] + " "); // 输出排序后的数组
		}
	}

	// 快速排序方法,参数为数组的起始和结束索引,以及数组本身
	static void quickSort(int l, int r, int[] a) {
		if (l >= r) { // 如果起始索引大于或等于结束索引,则直接返回
			return;
		}
		int i = l - 1, j = r + 1, x = a[l + r >> 1]; // 初始化指针i, j和基准元素x,以中间元素作为基准元素
		while (i < j) { // 当i小于j时,执行循环
			do {
				i++; // i指针向右移动,直到找到一个大于或等于x的元素
			} while (a[i] < x);
			do {
				j--; // j指针向左移动,直到找到一个小于或等于x的元素
			} while (a[j] > x);
			if (i < j) { // 如果i仍然小于j,交换这两个元素
				int tmp = a[i];
				a[i] = a[j];
				a[j] = tmp;
			}
		}
		quickSort(l, j, a); // 递归排序左半部分
		quickSort(j + 1, r, a); // 递归排序右半部分
	}

}

🔗参考

  • https://www.acwing.com/problem/content/787/
  • https://www.hello-algo.com/chapter_sorting/quick_sort/

作者:程序员何未来-heweilai.com


🔍推荐阅读

  1. 【七夕节实践】把爱心代码放在自己的网站上是什么体验?
  2. 塑造你的技术名片:写给程序员的个人品牌建设指南
  3. 博客赚钱全攻略:从新手到专家的变现之路

欢迎关注我的博客:@程序员何未来,持续为你输出有价值的技术文章~
你们的点赞👍 收藏⭐ 留言🗨️ 关注✅
是我持续创作,输出优质内容的最大动力!谢谢!

文章关键词:算法,计算机算法,算法题解,算法竞赛,Java,数据结构,AcWing算法基础课

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

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

相关文章

Axure打造科技感数据可视化大屏原型

在数字化浪潮的推动下&#xff0c;数据已成为企业决策不可或缺的核心驱动力。面对海量且复杂的数据集&#xff0c;如何高效解读并转化为洞见&#xff0c;是企业面临的重大挑战。数据可视化&#xff0c;尤其是科技感十足的大屏展示&#xff0c;不仅为企业提供了直观的数据洞察&a…

9,sql 约束

创建表时添加非空约束 create table sys3(name int,age int not null) 建表后修改 alter table sys3 modify name int null 删除 创建表时添加默认值约束 关键字 default 默认值的意思 后面跟着默认的值create table sys_4(列名1 数据类型 default 默认值,列名2 数据类型 no…

网络安全售前入门09安全服务——安全加固服务

目录 1.服务概述 2.流程及工具 2.1服务流程 2.2服务工具 3.服务内容 ​​​​​​​4.服务方式 ​​​​​​​5.风险规避措施 ​​​​​​​6.服务输出 1.服务概述 安全加固服务是参照风险评估、等保测评、安全检查等工作的结果,基于科学的安全思维方式、长期的安全…

Apache CloudStack Official Document 翻译节选(十三)

快速部署一朵 Apache CloudStack 云 &#xff08;二&#xff09; 部署一朵pache CloudStack 云 安装Apache CloudStack的云内管理服务组件 本部分我们将安装Apache CloudStack的云内管理服务组件及周边工具。 关于数据库的安装与配置&#xff1a; 我们会安装和配置MySQL并配…

【机器学习入门】一文读懂非线性支持向量机SVM

前面已经分别介绍了基于硬间隔最大化的线性可分支持向量机、基于软间隔最大化的线性支持向量机&#xff0c;这次来总结下使用核函数来解决非线性可分问题的非线性支持向量机。 【机器学习入门】一文读懂线性可分支持向量机【机器学习入门】一文读懂线性支持向量机SVM 一 非线…

GCViT实战:使用GCViT实现图像分类任务(一)

摘要 GC ViT&#xff08;全局上下文视觉转换器&#xff09;是一种创新的深度学习架构&#xff0c;旨在提升计算机视觉任务中的参数和计算效率。它通过将全局上下文自注意力模块与标准的局部自注意力相结合&#xff0c;有效地建模长程和短程空间交互&#xff0c;同时避免了传统…

IJCAI-信也科技杯全球AI大赛-华东师范大学亚军队伍分享

作者&#xff1a;彭欣怡(找不到工作版) 华东师范大学; 马千里(搬砖版) 虾皮; 指导&#xff1a;闫怡搏(科研版) 华东师范大学 比赛链接&#xff1a;https://ai.ppdai.com/mirror/goToMirrorDetailSix?mirrorId34 前言 这是我们首次参加语音领域的比赛&#xff0c;最初只是抱着…

深度学习之 OpenCV 图像边缘检测算法解析及代码演示

引言 在计算机视觉领域&#xff0c;边缘检测是一种重要的图像预处理技术&#xff0c;用于识别图像中对象的边界。边缘检测有助于提取图像的关键特征&#xff0c;这对于后续的图像分析&#xff08;如物体识别、运动检测等&#xff09;至关重要。OpenCV 是一个强大的计算机视觉库…

Zabbix 企业级高级应用(Zabbix Enterprise Advanced Application)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

备忘录1【java环境变量手动更改】

B站视屏链接&#xff1a;https://www.bilibili.com/video/BV1cV8BeCESA?vd_source3e4562475feb55327a8adde111050d4e 1.电脑设置 2.系统-------系统信息 3.高级系统设置 4.环境变量 5.系统变量中&#xff0c;更改之前创建好的JAVA_HOME 版本可以将1.8改成本机安装的其他版本…

Java进阶13讲__第九讲

Stream流 1. 案例初体验 package cn.hdc.oop9.stream.using;import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream;public class t1 {public static void main(String[] args) {LinkedList<String&g…

认知杂谈30

今天分享 有人说的一段争议性的话 I I 《豁然开朗&#xff1a;男性成长的关键转折》 在男人的人生旅程当中啊&#xff0c;最金贵的可不是那些让人眼馋的钱财啥的&#xff0c;也不是啥惊天动地的事儿&#xff0c;更不是偶尔碰到的贵人帮忙。真正无价的宝贝呢&#xff0c;是在…

培训第四十一天(docker-compose一键部署项目,haproxy容器代理多个web或java容器)

# 创建脚本&#xff0c;可以在java环境中运行任何的jar包或者war包#!/bin/bash/usr/local/jdk/bin/java -jar /java/src/*.?ar 一、思路分析&#xff1a; &#xff08;1&#xff09;nginx 1、下载镜像&#xff0c;将本地的dist项目的目录挂载在容器的/usr/share/nginx/html…

论文解读:Visual Prompt Tuning

Comment: ECCV2022 摘要 当前调整预训练模型的方法需要更新backbone的全部参数&#xff0c;即完全微调。本文提出了一种高效的方法VPT&#xff0c;成为视觉中大规模transformer模型完全微调的替代方案。从微调大规模语言模型中吸取经验&#xff0c;VPT仅在输入空间中引入少数…

【C语言】通讯录的实现(详解)

通讯录的实现 主要用到的知识&#xff1a; 1.结构体相关知识 2.枚举 3.多文件 在学习完结构体和枚举后就可以利用学过的知识去实现一个通讯录了 1.通讯录要求 用C语言所学知识实现下面这样一个通讯录 1.通讯录100个联系人 2.姓名 性别 年龄 电话 地址 3.添加联系人 4.删除指…

SQL server数据库实现远程跨服务器定时同步传输数据

项目背景 公司新建项目&#xff0c;需要访问生产数据&#xff0c;但是规定不能直接访问生产数据库服务器&#xff0c;所以得考虑通过中间库的形式实现。经过评估项目需求 &#xff0c;以及当前拥有的环境。 需求&#xff1a; 1.用户不需要实时获取生产数据 2.用户只需要指定的…

Python青少年简明教程:函数

Python青少年简明教程&#xff1a;函数 在Python中&#xff0c;函数是一段可重用的代码块&#xff0c;用于执行特定的任务。函数能够接受输入参数&#xff0c;执行特定的操作&#xff0c;并返回结果。 Python提供了许多内置函数&#xff0c;如print()、len()、eval()等&#x…

Java基于微信小程序的校园兼职小程序

博主介绍&#xff1a;✌stormjun、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

shadertoy-sdf 操作

vec3 col getBackgroundColor(uv); float d1 sdCircle(uv, 0.1, vec2(0., 0.)); float d2 sdSquare(uv, 0.1, vec2(0.15, 0));float res; // result1、union res min(d1, d2); // union2、intersection res max(d1, d2); // intersection3、subtraction res max(-d1, d…

Python实战案例数据合并订单表和商品价格表数据

有如下数据&#xff0c;订单表和商品价格表&#xff0c;进行数据合并&#xff0c;输出客户需要的效果。 数据样例&#xff1a;&#x1f447; 订单表: 商品价格表: 最终效果&#xff1a; 01实现思路 目的是将订单数据和商品价格数据按照商品id和时间进行匹配&#xff0c;以…