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 = array[high]; // 选择最后一个元素作为基准

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

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

if (array[j] < pivot) {

i++;

// 交换元素

int temp = array[i];

array[i] = array[j];

array[j] = temp;

}

}

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

int temp = array[i + 1];

array[i + 1] = array[high];

array[high] = 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 (array[low] > array[mid]) swap(array, low, mid);

if (array[low] > array[high]) swap(array, low, high);

if (array[mid] > array[high]) swap(array, mid, high);

return array[mid];

}

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

int temp = array[i];

array[i] = array[j];

array[j] = 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 (array[j] < 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 = array[high];

int i = low - 1;

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

if (array[j] < pivot) {

i++;

swap(array, i, j);

}

}

swap(array, i + 1, high);

return i + 1;

}

```

7. 快速排序的稳定性

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

相关推荐
0和1的舞者2 小时前
高并发论坛系统:单元测试 + 接口自动化 + 性能测试 + CI/CD 全链路测试报告
java·测试开发·测试工具·jmeter·pytest·测试·测试报告
空空kkk3 小时前
Java基础——代理
java·开发语言
野生技术架构师3 小时前
互联网大厂必备 Java 面试八股文真题解析
java·开发语言·面试
Rsun045513 小时前
synchronized关键字的底层实现
java
老约家的可汗3 小时前
C++篇之类和对象下
java·开发语言·c++
niuniudengdeng3 小时前
六面独立转动魔方还原机器人设计与实现
数学·算法·机器人
ghie90903 小时前
基于MATLAB的A*算法避障路径规划实现
人工智能·算法·matlab
€8113 小时前
Java入门级教程27——ActiveMQ的下载与应用
java·开发语言·activemq·点对点文本消息发送·点对点对象消息发送·mysql+redis·序列化对象消息传输
雾岛听蓝3 小时前
C文件操作与系统IO
linux·c语言·开发语言·经验分享·笔记·算法
zh路西法4 小时前
【宇树机器人强化学习】(一):PPO算法的python实现与解析
python·深度学习·算法·机器学习·机器人