快速排序:分而治之的高效排序算法
简介
快速排序是一种分而治之的排序算法,由C. A. R. Hoare在1960年提出。它通过选取一个元素作为"基准"(pivot),然后重新排列数组,使得所有比基准值小的元素都在基准的左边,所有比基准值大的元素都在基准的右边。这个过程称为分区(partitioning)。之后,递归地对基准左边和右边的子数组进行同样的操作。
算法步骤
- 从数组中选择一个元素作为基准。
- 重新排列数组,所有比基准小的元素移动到基准的左边,其余的移动到右边。
- 对基准左边和右边的子数组递归执行步骤1和2。
- 当所有子数组的大小为1或0时,排序完成。
java
//partition 方法接受数组、起始索引和结束索引作为参数,执行分区操作,并返回基准的索引位置。
//quickSort 方法是递归方法,它调用自身来排序基准左边和右边的子数组。
//main 方法中,我们初始化一个数组,然后调用 quickSort 方法进行排序,并打印排序后的结果。
public class QuickSort {
// 快速排序的分区操作
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // 选择最右侧的元素作为基准
int i = (low - 1); // Index of smaller element
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;
}
}
// 交换 arr[i+1] 和 arr[high] (或基准)
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 pi = partition(arr, low, high);
// 分别对左右分区递归排序
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
public static void main(String[] args) {
int[] arr = {10, 7, 8, 9, 1, 5};
quickSort(arr, 0, arr.length - 1);
// 打印排序后的数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
优点
- 效率:平均情况下,快速排序的时间复杂度为O(n log n),是最快的排序算法之一。
- 空间优势:空间复杂度为O(log n),递归实现时需要栈空间。
- 原地排序:快速排序是原地排序算法,不需要额外的存储空间来创建另一个数组。
缺点
- 最坏情况:在最坏情况下,时间复杂度退化为O(n^2),特别是当数组已经排序或所有元素相等时。
- 稳定性:快速排序是不稳定的排序算法,相同的元素可能在排序后改变它们原来的顺序。
- 递归实现:递归实现可能导致栈溢出,尤其是在数据量很大时。
时间复杂度和空间复杂度分析
- 时间复杂度:平均情况下为O(n log n),最坏情况下为O(n^2)。
- 空间复杂度:O(log n),这是递归调用所需的栈空间。
使用场景
- 快速排序适用于大多数需要排序的场景,特别是数据量较大时。
- 当数据分布均匀时,快速排序的性能最佳。