news 2026/6/26 6:55:07

快速排序算法java实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
快速排序算法java实现

快速排序是一种基于分治的排序算法,它选择一个元素作为枢轴,并通过将该枢轴置于排序后的数组中正确位置来划分。

该算法主要包含三个步骤:

选择枢轴:从数组中选择一个元素作为枢轴。枢轴的选择可以有所不同(例如,第一元素、最后元素、随机元素或中位数)。
数组划分:重新排列数组围绕枢轴。划分后,所有小于枢轴的元素位于其左侧,所有大于枢轴的元素位于其右侧。
递归调用:递归地将相同进程应用于两个分区子数组。
基础情况:当子数组中只剩一个元素时,递归停止,因为单个元素已被排序。

枢轴选择
选择枢轴有很多不同的选择。

始终选择第一个(或最后一个)元素作为枢轴。下面的实现选择了最后一个元素作为枢轴。这种方法的问题在于,最坏的情况往往是数组已经排序好。
随机选一个元素作为枢轴。这是一种首选方法,因为它没有最坏情况发生的模式。
选择中位数元素是枢轴。从时间复杂度角度看,这是一种理想的方法,因为我们可以在线性时间内找到中位数,且配分函数总是将输入数组分为两半。但平均来说需要更多时间,因为中位数的发现常数很高。
划分算法
快速排序中的密钥进程是一个分区()。 有三种常见的划分算法。所有这些算法的时间复杂度均为O(n)。

朴素划分:这里我们创建数组的副本。先放所有较小的元素,然后放更大的。最后,我们将临时数组复制回原始数组。这需要 O(n) 额外的空间。
洛穆托分区:本文中使用了该分区。这是一个简单的算法,我们跟踪较小元素的索引并不断交换。本文中我们使用它,因为它非常简单。
霍尔分区:这是所有分区中最快的。这里我们从两侧遍历数组,并在数组未分割的情况下不断交换左侧较大元素与右侧较小元素。详情请参阅Hoare对Lomuto的对决。
Lomuto划分算法的工作原理及示意图
逻辑很简单,我们从最左边的元素开始,并跟踪较小(或相等)元素的索引,作为 i。在遍历过程中,如果发现一个较小的元素,我们会将当前元素与 arr[i] 交换。否则,我们忽略当前元素。


重定向图标
让我们通过以下示例来理解分区算法的工作原理:


快速排序算法示意
在前一步,我们研究了分区过程如何根据所选枢轴重新排列数组。接下来,我们递归地将同样的方法应用到枢轴左右两个较小的子数组 。每次我们都选择新的枢轴点并再次划分数组。这个过程会持续,直到只剩下一个元素,并且总是被排序。一旦每个元素都处于正确位置,整个数组就被排序。

下图展示了递归方法如何调用枢轴左右两个较小子数组:

import java.util.Arrays; class GfG { // partition function static int partition(int[] arr, int low, int high) { // choose the pivot int pivot = arr[high]; // index of smaller element and indicates // the right position of pivot found so far int i = low - 1; // traverse arr[low..high] and move all smaller // elements to the left side. Elements from low to // i are smaller after every iteration for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; swap(arr, i, j); } } // Move pivot after smaller elements and // return its position swap(arr, i + 1, high); return i + 1; } // swap function static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } // the QuickSort function implementation static void quickSort(int[] arr, int low, int high) { if (low < high) { // pi is the partition return index of pivot int pi = partition(arr, low, high); // recursion calls for smaller elements // and greater or equals elements quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } public static void main(String[] args) { int[] arr = {10, 7, 8, 9, 1, 5}; int n = arr.length; quickSort(arr, 0, n - 1); for (int val : arr) { System.out.print(val + " "); } } }

输出
1 5 7 8 9 10
快速排序的复杂度分析
时间复杂性:

最佳情况:(Ω(n log n)),当枢轴元素将数组分为两个相等的一半时发生。
平均情况 (θ(n log n)),平均而言,枢轴将数组分为两部分,但不一定相等。
最坏情况:(O(n²)),当始终选择最小或最大元素作为枢轴时(例如,已排序的数组)。
辅助空间:

最坏情况:由于不平衡划分导致递归树倾斜,需要调用栈大小为 O(n) 的 O(n)。
最佳情况:由于平衡分区,O(log n) 生成了一个具有调用栈大小为 O(log n) 的平衡递归树。
详情请参阅快速排序的时间与空间复杂性分析。

快速排序的优势
它是一种分而治之的算法,使解决问题变得更容易。
它在大数据集上效率很高。
它开销低,只需少量内存即可运行。
它对缓存友好,因为我们在同一数组上进行排序,且不会将数据复制到任何辅助数组。
在不需要稳定性的情况下,是处理大数据的最快通用算法。
它是尾部递归的,因此所有尾调用优化都是可以完成的。
快速排序的缺点
其最坏时间复杂度为 O(n)2),当枢轴选择不当时,就会发生这种情况。
对于小型数据集来说,它并不是一个好的选择。
它不是稳定排序,意味着如果两个元素键相同,快速排序时它们的相对顺序不会在排序输出中保持,因为这里我们根据枢轴的位置交换元素(不考虑它们的原始位置)。
快速排序的应用
高效地在内存中排序大型数据集。
用于库的排序函数(如 C++ std::sort 和 Java Arrays.sort 用于原语)。
在数据库中整理记录以加快搜索速度。
需要排序输入的算法中的预处理步骤(例如,二分搜索、两点技术)。
使用快速选择(Quicksort 的一种变体)找到第 k 个最小/最大的元素。
基于多个键(自定义比较器)排序对象数组。
数据压缩算法(如霍夫曼编码预处理)。
图形学和计算几何(例如凸包算法)。

编程资源 https://pan.quark.cn/s/7f7c83756948 更多资源 https://pan.quark.cn/s/bda57957c548
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/24 11:31:50

【Matlab】MATLAB矩阵点乘运算详解:逐元素相乘案例与加权计算应用

MATLAB矩阵点乘运算详解:逐元素相乘案例与加权计算应用 在MATLAB数值计算中,矩阵点乘(也称为元素级乘法,语法为A.*B)是与矩阵线性乘法(A*B)并列的核心运算,其核心逻辑是“两个同维度矩阵的对应元素逐一相乘”,无矩阵线性乘法的行列匹配约束,却兼具灵活的元素级操作特…

作者头像 李华
网站建设 2026/6/21 14:50:35

【个人成长】樊登访谈:创业、读书与成长的底层逻辑

樊登访谈&#xff1a;创业、读书与成长的底层逻辑 一、创业初期&#xff1a;反脆弱的生存智慧 1. 艰难但理性的起步 刚到北京时&#xff0c;央视的工资很不稳定——有节目时工资高,没节目时就低。但我是一个反脆弱性比较强的人&#xff0c;会考虑风险考虑得比较多。我觉得万…

作者头像 李华
网站建设 2026/6/25 16:33:18

基于php技术的广告公司网站方案设计与实现 开题报告

目录 研究背景与意义技术选型分析核心功能模块设计创新点与难点预期成果进度计划 项目技术支持可定制开发之功能亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作 研究背景与意义 广告公司网站作为品牌展示与业务拓展的核心平台&#xf…

作者头像 李华