java-快速排序 1

Java中的快速排序

1. 快速排序的基本概念

快速排序(Quick Sort)是一种高效的排序算法,由Tony Hoare在1960年提出。它采用分治法(Divide and Conquer)策略来将一个数组分成较小的子数组,并分别对它们进行排序。快速排序通常被认为是最实用的排序算法之一,因为它在大多数情况下具有非常好的平均性能。

2. 快速排序的工作原理

快速排序的核心思想是通过一个称为"基准"(Pivot)的元素将数组分为两部分,使得基准左侧的元素都小于基准,右侧的元素都大于基准。然后,递归地对左右两部分进行同样的操作,直到整个数组有序。

2.1 分治法

快速排序使用分治法,将问题递归地分解成更小的子问题。具体步骤如下:

  1. **选择基准**:从数组中选择一个元素作为基准,通常选择第一个元素或最后一个元素。

  2. **划分数组**:重排数组,使得基准左侧的元素都小于基准,右侧的元素都大于基准。

  3. **递归排序**:递归地对基准左侧和右侧的子数组进行排序。

2.2 示例

假设有一个待排序的数组 `10, 7, 8, 9, 1, 5`,快速排序的过程如下:

  1. 选择基准元素,假设选择最后一个元素 `5`。

  2. 划分数组,将小于 `5` 的元素移到左侧,大于 `5` 的元素移到右侧,得到 `1, 7, 8, 9, 10, 5`。

  3. 基准 `5` 已经在正确的位置,现在对左侧 `1, 7, 8, 9, 10` 和右侧空数组进行递归排序。

  4. 重复上述步骤,直到数组有序。

3. 快速排序的实现

在Java中实现快速排序可以使用递归方法,下面是详细的实现步骤。

3.1 基本实现

```java

public class QuickSort {

// 快速排序主方法

public static void quickSort(int\[\] array, int low, int high) {

if (low < high) {

// 找到划分点

int pi = partition(array, low, high);

// 递归排序划分点左侧的数组

quickSort(array, low, pi - 1);

// 递归排序划分点右侧的数组

quickSort(array, pi + 1, high);

}

}

// 划分方法

private static int partition(int\[\] array, int low, int high) {

int pivot = arrayhigh; // 选择最后一个元素作为基准

int i = low - 1; // i指向小于基准的区域的最后一个元素

for (int j = low; j < high; j++) {

if (arrayj < pivot) {

i++;

// 交换元素

int temp = arrayi;

arrayi = arrayj;

arrayj = temp;

}

}

// 交换基准元素到正确的位置

int temp = arrayi + 1;

arrayi + 1 = arrayhigh;

arrayhigh = temp;

return i + 1;

}

public static void main(String\[\] args) {

int\[\] array = {10, 7, 8, 9, 1, 5};

quickSort(array, 0, array.length - 1);

System.out.println("Sorted array:");

for (int i : array) {

System.out.print(i + " ");

}

}

}

```

在这个实现中,`quickSort`方法是快速排序的主方法,它递归地对数组进行排序。`partition`方法是划分数组的方法,它选择一个基准元素,并将数组划分为两部分。

4. 快速排序的时间复杂度

快速排序的时间复杂度取决于选择基准的策略和输入数组的初始顺序:

  • **最好情况**:每次划分都能将数组均匀地分成两部分,时间复杂度为 O(n log n)。

  • **最坏情况**:每次划分只能减少一个元素,例如输入数组已经有序或逆序,时间复杂度为 O(n^2)。

  • **平均情况**:通过随机选择基准或三数取中法等策略,可以避免最坏情况,平均时间复杂度为 O(n log n)。

5. 快速排序的空间复杂度

快速排序的空间复杂度主要由递归调用栈的深度决定:

  • **最好情况**:递归调用栈的深度为 O(log n)。

  • **最坏情况**:递归调用栈的深度为 O(n)。

  • **平均情况**:递归调用栈的深度为 O(log n)。

6. 快速排序的优化

为了提高快速排序的性能,可以进行以下优化:

6.1 三数取中法

选择基准时,使用三数取中法可以避免选择最小或最大的元素作为基准,从而避免最坏情况。

```java

private static int medianOfThree(int\[\] array, int low, int high) {

int mid = (low + high) / 2;

if (arraylow > arraymid) swap(array, low, mid);

if (arraylow > arrayhigh) swap(array, low, high);

if (arraymid > arrayhigh) swap(array, mid, high);

return arraymid;

}

private static void swap(int\[\] array, int i, int j) {

int temp = arrayi;

arrayi = arrayj;

arrayj = temp;

}

private static int partition(int\[\] array, int low, int high) {

int pivot = medianOfThree(array, low, high);

int i = low - 1;

for (int j = low; j < high; j++) {

if (arrayj < pivot) {

i++;

swap(array, i, j);

}

}

swap(array, i + 1, high);

return i + 1;

}

```

6.2 随机选择基准

随机选择基准可以避免最坏情况的发生,保证平均时间复杂度为 O(n log n)。

```java

private static int partition(int\[\] array, int low, int high) {

int pivotIndex = low + (int)(Math.random() * (high - low + 1));

swap(array, pivotIndex, high);

int pivot = arrayhigh;

int i = low - 1;

for (int j = low; j < high; j++) {

if (arrayj < pivot) {

i++;

swap(array, i, j);

}

}

swap(array, i + 1, high);

return i + 1;

}

```

7. 快速排序的稳定性

快速排序不是一个稳定的排序算法,因为在划分过程中,相等元素的相对顺序可能会改变。然而,快速排序可以通过一些改进来实现稳定性,但这通常会增加算法的复杂性和开销。

相关推荐
To_OC6 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
小bo波10 小时前
使用Thread子类创建线程 VS 使用Runnable接口创建线程的区别
java·多线程·thread·并发编程·runnable
SamDeepThinking11 小时前
高并发场景下,CompletableFuture与ForkJoinPool该如何取舍?
java·后端·面试
用户9385156350711 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
To_OC13 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥13 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
张不才14 小时前
CPU 100% 了怎么办?Java 性能排障的标准化操作
java·后端
地平线开发者14 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者15 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
shepherd11115 小时前
吞吐量提升 10 倍:高并发大批量数据处理任务的架构演进与性能调优
java·后端·架构