23. 快速排序:实现快速排序算法
大约 3 分钟
快速排序(Quick Sort)是一种基于分治法的排序算法。它通过选择一个基准(pivot),将数组分为两个子数组,然后递归地对这两个子数组进行排序。快速排序的平均时间复杂度为 O(n log n)
,在最坏情况下(例如,输入数组已经排序),时间复杂度为 O(n^2)
。
一、快速排序算法的基本思想
- 选择基准:从数组中选择一个元素作为基准(pivot)。
- 分区:重新排序数组,使得所有比基准小的元素放在基准的左边,所有比基准大的元素放在基准的右边。在这个分区操作完成后,基准就处于其最终位置。
- 递归排序:递归地对基准左右两侧的子数组进行排序。
二、代码实现
下面是使用 Java 实现快速排序的代码示例。
1. 主函数和辅助函数
public class QuickSort {
// 快速排序的主函数
public 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);
}
}
// 分区函数,选择最后一个元素为基准
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]
swap(arr, i, j);
}
}
// 交换基准到正确的位置
swap(arr, i + 1, high);
return i + 1; // 返回基准的索引
}
// 交换数组中的两个元素
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {10, 7, 8, 9, 1, 5};
int n = arr.length;
quickSort(arr, 0, n - 1);
System.out.println("Sorted array:");
for (int num : arr) {
System.out.print(num + " ");
}
}
}
2. 代码详解
- quickSort 函数:这是快速排序的主函数。它接收一个数组和两个索引
low
和high
,用于对数组的这个部分进行排序。通过递归调用,quickSort
函数会逐渐对整个数组进行排序。 - partition 函数:这是快速排序的关键部分。
partition
函数将数组重新排列,使得所有小于基准的元素位于基准的左侧,大于基准的元素位于右侧,并返回基准元素的正确位置。 - swap 函数:用于交换数组中两个元素的位置。
- main 函数:这是程序的入口。它定义了一个数组,调用
quickSort
函数对数组进行排序,并输出排序后的结果。
三、快速排序的时间复杂度
- 平均时间复杂度:
O(n log n)
,这是快速排序的期望时间复杂度。每次分区大致将数组分成两半,所以需要log n
次递归调用,每次递归调用处理n
个元素。 - 最坏时间复杂度:
O(n^2)
,当每次选择的基准都无法将数组均匀分割时,例如数组已经排序或逆序时,会导致最坏的分区结果。 - 空间复杂度:
O(log n)
,这是由于递归调用栈的深度决定的。最坏情况下(如已经排序的数组),递归调用栈的深度可能达到O(n)
,但平均情况下是O(log n)
。
四、总结
快速排序是一种高效的排序算法,广泛应用于实际开发中。尽管在最坏情况下它的时间复杂度为 O(n^2)
,但通过优化(例如随机选择基准、三数取中法选择基准)可以有效降低最坏情况发生的概率,从而保持其平均时间复杂度 O(n log n)
的高效性。