快速排序算法的 Java 实现与性能调优

目录

一、快速排序的基本原理

二、快速排序的 Java 实现

三、时间复杂度与空间复杂度

四、总结


引言
排序是计算机科学中的基础问题之一,无论是在数据库查询、数据分析,还是在日常编程中,排序算法的选择都对性能有着重要的影响。快速排序(Quick Sort) 是最广泛使用的排序算法之一,因其高效的平均时间复杂度和较小的空间复杂度,广泛应用于实际生产环境中。
本文将深入讲解快速排序算法的原理,并通过 Java 代码实现其功能,同时分析其性能特点和优化策略。

一、快速排序的基本原理

快速排序是一种基于分治法(Divide and Conquer)的排序算法,其核心思想是:

1.选择一个基准元素(pivot),将待排序的数组分成两部分:

(1)一部分所有元素都小于或等于基准元素。
(2)另一部分所有元素都大于基准元素。
(3)对这两部分递归地进行排序。

1.1 分区操作(Partition)

快速排序的关键步骤是分区操作,目标是将数组根据基准元素分为两个部分。具体过程如下:

(1)选择一个元素作为基准,通常是数组的第一个元素、最后一个元素或中间元素。
(2)遍历数组,将所有小于基准的元素移动到基准的左侧,大于基准的元素移动到基准的右侧。
(3)将基准元素放置到它的正确位置上,左侧元素都小于它,右侧元素都大于它。

1.2 递归排序

分区完成后,基准元素已经处于其正确的位置。然后对基准元素左边和右边的两个子数组进行递归排序。递归的停止条件是数组只有一个元素或为空,此时已经是有序的。

二、快速排序的 Java 实现

2.1 Java 代码

public class QuickSort {// 分区操作,返回基准元素的最终位置
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准
int i = low - 1; // i 是比基准小的元素的索引
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
// 交换 arr[i] 和 arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 将基准元素放到正确的位置
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;return i + 1; // 返回基准元素的位置
}// 快速排序递归函数
private static void quickSort(int[] arr, int low, int high) {
if (low < high) {
// 获取分区后的基准元素的正确位置
int pivotIndex = partition(arr, low, high);// 分别对基准元素左右的子数组进行排序
quickSort(arr, low, pivotIndex - 1); // 排序左边
quickSort(arr, pivotIndex + 1, high); // 排序右边
}
}// 主函数,快速排序的入口
public static void quickSortMain(int[] arr) {
quickSort(arr, 0, arr.length - 1);
}// 测试
public static void main(String[] args) {
int[] arr = {10, 7, 8, 9, 1, 5};
quickSortMain(arr);
System.out.println("Sorted array:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}

2.2 代码解释

(1)partition 方法:该方法接收一个数组和低高索引,将基准元素与数组的其他元素进行比较并交换,最终将基准元素放到正确的位置,返回该位置的索引。

(2)quickSort 方法:这是递归方法。它调用 partition 方法对数组进行分区,然后分别对分区后的两个子数组进行递归排序。

(3)quickSortMain 方法:这是外部调用的入口方法,用于启动快速排序。它调用 quickSort 方法,传入数组的起始和结束索引。

(4)main 方法:用于测试和验证排序效果。我们定义了一个无序数组,然后调用 quickSortMain 方法进行排序,最后输出排序后的结果。

2.3 测试结果

运行程序时,输入数组 {10, 7, 8, 9, 1, 5},输出结果为:

Sorted array:
1 5 7 8 9 10 

三、时间复杂度与空间复杂度

3.1 时间复杂度

(1)最佳情况(Best Case):当数组被平均分割时,每次分区的工作量减少一半,递归的深度为 log n。此时的时间复杂度为 O(n log n)。

(2)最坏情况(Worst Case):最坏情况下,数组已经是有序的或者是逆序的。此时每次分区只分割出一个元素,递归的深度为 n。最坏情况的时间复杂度为 O(n^2)。

(3)平均情况(Average Case):快速排序的平均情况通常是理想的分割,时间复杂度是 O(n log n)。

3.2 空间复杂度

(1)空间复杂度:由于快速排序是递归实现,递归调用需要栈空间。空间复杂度为 O(log n),这是递归树的高度。最坏情况下,空间复杂度为 O(n),当数组非常不平衡时。

3.3 优化

(1)基准选择的优化:

在选择基准时,常常使用数组的第一个元素、最后一个元素或中间元素作为基准。为了避免最坏情况,可以使用三数取中法,即选择数组的第一个、最后一个和中间元素中的中位数作为基准,从而有效避免退化成 O(n^2) 的情况。

(2)尾递归优化:

在实际实现中,可以通过尾递归优化将空间复杂度降到最小,通常优先递归较小的子数组,较大的子数组采用循环来处理。

四、总结

快速排序因其平均时间复杂度为 O(n log n),并且其实现简单、效率高,在大多数情况下比其他排序算法(如归并排序、堆排序等)更具优势,尤其是在数组较大时。然而,在最坏情况下,快速排序的性能会退化为 O(n^2)。为了优化其性能,可以采用合适的基准选择策略和尾递归优化。

在实际应用中,Java 标准库中的 Arrays.sort() 使用的就是一种优化后的快速排序实现。理解和掌握快速排序的原理及其优化方式,对于程序员提高算法设计与分析能力具有重要意义。

希望通过这篇文章,大家能够更好地理解快速排序的基本思想,并能够在实际编程中灵活运用这一高效的排序算法。

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

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

相关文章

如何利用无线路由器实现水泵房远程监测管理

水泵站广泛部署应用在工农业用水、防洪、排涝和抗旱减灾等方面,如果水泵站发生异常,往往会对生产生活造成诸多损失,甚至引发安全事故。因此,建立一套高效、可靠的泵站远程监测管理系统至关重要。 方案背景 目前,我国大…

解锁健康步姿密码:无标记点动作捕捉系统助力医疗康复

在医疗康复领域,精准的步态分析对于患者进行正常行走能力恢复检测起着举足轻重的作用。AI 无标记点动作捕捉系统基于先进的深度学习视觉算法,实现了对人体的全方位动作捕捉,为医疗康复步态分析提供了全新的解决方案。 无标记点动作捕捉系统在…

vue封装弹窗元素拖动指令

项目开发过程中我们通常会遇到需要到一些弹窗鼠标可以随意拖动位置去放置,vue里面直接通过封装对应的指令即可,于是封装了一个出来,希望可以用到。 Vue.directive(draggable-dom, draggableDom); 组件节点添加对应指令就可以 v-draggable-…

将广播发送和接收端实现一遍,完成一个发送端发送信息,对应多个接收端接收信息实验。

1、将广播发送和接收端实现一遍&#xff0c;完成一个发送端发送信息&#xff0c;对应多个接收端接收信息实验。 接受端 #include<myhead.h> #define handel_err(res,val) if(val-1){perror(res);return-1;} int main(int argc, const char *argv[]) {int rfdsocket(AF_…

基本算法——聚类

目录 创建工程 加载数据 聚类算法 评估 完整代码 结论 相比于有监督的分类器&#xff0c;聚类的目标是从一组未打标签的数据中识别相似对象组。它可 以用于识别同类群体的代表性样本&#xff0c;找到有用与合适的分组&#xff1b;或者找到不寻常的样本&#xff0c;比如 异…

uniapp中的条件编译

在script中 // #ifdef APP-PLUS console.log("11"); // #endif// #ifdef MP-WEIXIN console.log("22"); // #endif 在template中 <!-- #ifdef APP-PLUS --><view>哈哈哈</view> <!-- #endif --><!-- #ifdef MP-WEIXIN -->…

day21-ubuntu入门

小趣味docker 1.安装docker&#xff0c;从阿里云的yum yum install docker -y 2.需要提前准备好docker镜像&#xff0c;确保可用 docker -v 3.导入该游戏镜像&#xff08;先用systemctl start docker&#xff09; docker load < game_v2.tar 4.一条命令&#xff0c;在…

vue3 学习与实战

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#xff0c;最…

Three.js滚动画案例精选

今天为大家带来 3 个基于滚动动画的网站 Demo&#xff0c;它们不仅视觉效果惊艳&#xff0c;而且每个案例的源码都已开源在 GitHub&#xff0c;方便大家学习和借鉴&#xff01; 3D照片墙滚动 通过滚动操作实现 3D 网格效果以及动态过渡动画。这个案例使用了 GSAP 的 SplitTex…

地理数据库Telepg面试内容整理-描述你如何在GIS应用中使用空间数据进行分析并生成可视化结果

在 GIS(地理信息系统)应用中,使用空间数据进行分析并生成可视化结果是一项关键功能。空间数据的分析和可视化帮助用户理解地理现象、发现模式,并做出数据驱动的决策。以下是一个关于如何在 GIS 应用中使用空间数据进行分析并生成可视化结果的详细描述。 准备空间数据 在进行…

若依(spring-cloud)修改登陆密码加密算法

文章目录 前言一、解决办法二、解决过程1 为啥要改加密算法2 找不到校验代码 总结 前言 若依是一套快速集成各种中间件的配套 Java 后端框架&#xff0c;本文旨在描述修改其登陆的加密算法。文章的大前提是后端框架是若依哈&#xff0c;不是的话可以跳过了~&#xff01; 文章…

Flutter富文本实现学习

Flutter 代码如何实现一个带有富文本显示和交互的页面。 前置知识点学习 RealRichText RealRichText 和 ImageSpan 不是 Flutter 框架中内置的组件&#xff0c;而是自定义的组件或来自第三方库。这些组件的实现可以提供比标准 RichText 更丰富的功能&#xff0c;比如在富文本…

MBox20边缘计算网关助力各种数字化升级

在当今全球范围内数字化浪潮的强劲推动下&#xff0c;企业对数据处理与传输能力的需求正以前所未有的速度增长。制造业的心脏地带——工厂&#xff0c;其数字化转型已成为驱动生产效率飞跃、成本控制优化及竞争力显著提升的关键路径。在此过程中&#xff0c;明达技术MBox20边缘…

el-table动态行和列及多级表头

主页面 <template><div class"result-wrapper"><dynamic-table :table-data"tableData" :table-header"tableConfig" :tableTitle"tableTitle" :flowParams"flowParams"></dynamic-table></div…

RocketMQ(二)RocketMQ实战

文章目录 一、RocketMQ实战1.1 批量消息发送1.2 消息发送队列自选择1.3 事务消息1.4 SpringCloud集成RocketMQ 二、最佳实践2.1 生产者2.1.1 发送消息注意事项2.1.2 消息发送失败处理方式 2.2 消费者2.2.1 消费过程幂等2.2.2 消费打印日志 2.3 Broker 三、相关问题3.1 为什么要…

2-194基于matlab的四足机器人行走程序设计

基于matlab的四足机器人行走程序设计&#xff0c;正运动设计&#xff0c;逆运动学解算&#xff0c;步态设计。可定义机身高、步长、步高、一个摆相的市场等参数。输出四足机器人动态行走结果&#xff0c;及摆相示意图。程序已调通&#xff0c;可直接运行。 2-194基于matlab的四…

android studio android sdk下载地址

android studio安装后&#xff0c;因为公司网络原因&#xff0c;一直无法安装android sdk 后经过手机网络&#xff0c;安装android sdk成功如下&#xff0c;也可以手动下载后指定android sdk本地目录 https://dl.google.com/android/repository/source-35_r01.zip https://dl…

字符串和对象之间的转换

使用&#xff1a; <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version> </dependency> public class Demo3 {public static void main(String[] args) {Person person …

conda常用维护命令

文章目录 1. 初始化和更新 Conda更新 Conda初始化 Conda&#xff08;如果需要&#xff09; 2. 管理环境创建新环境激活环境停用当前环境列出所有环境删除环境 3. 管理包安装包卸载包更新包更新所有包查找包列出已安装包 4. 导入导出环境导出环境配置从文件创建环境 5. 管理通道…

window如何将powershell以管理员身份添加到右键菜单?(按住Shift键显示)

window如何将powershell以管理员身份添加到右键菜单&#xff1f; 在 Windows 中&#xff0c;将 PowerShell 以管理员身份添加到右键菜单&#xff0c;可以让你在需要提升权限的情况下快速打开 PowerShell 窗口。以下是详细的步骤&#xff0c;包括手动编辑注册表和使用注册表脚本…