## C++ 快速排序
简介
快速排序 (Quicksort) 是一种高效的排序算法,其平均时间复杂度为 O(n log n),最坏时间复杂度为 O(n²),但实际应用中表现通常优异。它基于分治的思想,通过递归将一个大问题分解成若干个小问题来解决。 快速排序的效率很大程度上取决于所选择的枢轴 (pivot) 元素。### 1. 算法原理快速排序的核心思想是:1.
选择枢轴:
从数组中选择一个元素作为枢轴。枢轴的选择策略会影响算法的性能。常用的策略包括:选择第一个元素、最后一个元素、中间元素或随机选择。2.
分区:
将数组划分成两个子数组,一个子数组包含所有小于枢轴的元素,另一个子数组包含所有大于枢轴的元素。 枢轴元素最终会处于其排序后的正确位置。3.
递归:
递归地对两个子数组进行排序。### 2. 代码实现以下是一个基于 Lomuto 分区方案的 C++ 快速排序实现:```cpp
#include
#include void quicksort(std::vector& arr, int low, int high) {if (low < high) {int pivotIndex = partition(arr, low, high); // 获取枢轴索引quicksort(arr, low, pivotIndex - 1); // 递归排序左子数组quicksort(arr, pivotIndex + 1, high); // 递归排序右子数组}
}int partition(std::vector& arr, int low, int high) {int pivot = arr[high]; // 选择最后一个元素作为枢轴int i = (low - 1); // 指向小于枢轴元素的最后一个位置for (int j = low; j <= high - 1; j++) {if (arr[j] < pivot) {i++;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);return (i + 1);
}int main() {std::vector arr = {10, 7, 8, 9, 1, 5};int n = arr.size();quicksort(arr, 0, n - 1);std::cout << "排序后的数组:";for (int i = 0; i < n; i++)std::cout << arr[i] << " ";std::cout << std::endl;return 0;
}
```### 3. 不同的分区方案除了上面使用的 Lomuto 分区方案,还有 Hoare 分区方案。Hoare 方案通常被认为更有效率,因为它只需要遍历数组一次。 然而,Lomuto 方案更容易理解和实现。
Hoare 分区方案示例:
```cpp
int partitionHoare(std::vector& arr, int low, int high) {int pivot = arr[(low + high) / 2]; // 选择中间元素作为枢轴int i = low - 1;int j = high + 1;while (true) {do {i++;} while (arr[i] < pivot);do {j--;} while (arr[j] > pivot);if (i >= j) {return j;}std::swap(arr[i], arr[j]);}
}
```### 4. 时间复杂度分析
平均时间复杂度:
O(n log n)
最坏时间复杂度:
O(n²) (发生在数组已经排序或接近排序,以及选择不佳的枢轴时)
最佳时间复杂度:
O(n log n)
空间复杂度:
O(log n) (由于递归调用,空间复杂度与递归深度成正比)### 5. 改进策略为了减少快速排序出现最坏情况的概率,可以采用以下策略:
随机选择枢轴:
随机选择枢轴可以有效地避免最坏情况的发生。
三数取中法:
选择三个元素(例如,第一个、中间和最后一个元素)中的中位数作为枢轴。
插入排序优化:
当子数组较小时(例如,小于某个阈值),使用插入排序代替快速排序,可以提高效率。### 6. 总结快速排序是一种非常实用的排序算法,其平均性能非常优秀。 理解不同的分区方案和优化策略,可以帮助你更好地应用快速排序算法。 选择合适的枢轴策略和处理小数组的方式对于算法的实际效率至关重要。
C++ 快速排序**简介**快速排序 (Quicksort) 是一种高效的排序算法,其平均时间复杂度为 O(n log n),最坏时间复杂度为 O(n²),但实际应用中表现通常优异。它基于分治的思想,通过递归将一个大问题分解成若干个小问题来解决。 快速排序的效率很大程度上取决于所选择的枢轴 (pivot) 元素。
1. 算法原理快速排序的核心思想是:1. **选择枢轴:** 从数组中选择一个元素作为枢轴。枢轴的选择策略会影响算法的性能。常用的策略包括:选择第一个元素、最后一个元素、中间元素或随机选择。2. **分区:** 将数组划分成两个子数组,一个子数组包含所有小于枢轴的元素,另一个子数组包含所有大于枢轴的元素。 枢轴元素最终会处于其排序后的正确位置。3. **递归:** 递归地对两个子数组进行排序。
2. 代码实现以下是一个基于 Lomuto 分区方案的 C++ 快速排序实现:```cpp
include
include void quicksort(std::vector& arr, int low, int high) {if (low < high) {int pivotIndex = partition(arr, low, high); // 获取枢轴索引quicksort(arr, low, pivotIndex - 1); // 递归排序左子数组quicksort(arr, pivotIndex + 1, high); // 递归排序右子数组}
}int partition(std::vector& arr, int low, int high) {int pivot = arr[high]; // 选择最后一个元素作为枢轴int i = (low - 1); // 指向小于枢轴元素的最后一个位置for (int j = low; j <= high - 1; j++) {if (arr[j] < pivot) {i++;std::swap(arr[i], arr[j]);}}std::swap(arr[i + 1], arr[high]);return (i + 1);
}int main() {std::vector arr = {10, 7, 8, 9, 1, 5};int n = arr.size();quicksort(arr, 0, n - 1);std::cout << "排序后的数组:";for (int i = 0; i < n; i++)std::cout << arr[i] << " ";std::cout << std::endl;return 0;
}
```
3. 不同的分区方案除了上面使用的 Lomuto 分区方案,还有 Hoare 分区方案。Hoare 方案通常被认为更有效率,因为它只需要遍历数组一次。 然而,Lomuto 方案更容易理解和实现。**Hoare 分区方案示例:**```cpp
int partitionHoare(std::vector& arr, int low, int high) {int pivot = arr[(low + high) / 2]; // 选择中间元素作为枢轴int i = low - 1;int j = high + 1;while (true) {do {i++;} while (arr[i] < pivot);do {j--;} while (arr[j] > pivot);if (i >= j) {return j;}std::swap(arr[i], arr[j]);}
}
```
4. 时间复杂度分析* **平均时间复杂度:** O(n log n)
* **最坏时间复杂度:** O(n²) (发生在数组已经排序或接近排序,以及选择不佳的枢轴时)
* **最佳时间复杂度:** O(n log n)
* **空间复杂度:** O(log n) (由于递归调用,空间复杂度与递归深度成正比)
5. 改进策略为了减少快速排序出现最坏情况的概率,可以采用以下策略:* **随机选择枢轴:** 随机选择枢轴可以有效地避免最坏情况的发生。
* **三数取中法:** 选择三个元素(例如,第一个、中间和最后一个元素)中的中位数作为枢轴。
* **插入排序优化:** 当子数组较小时(例如,小于某个阈值),使用插入排序代替快速排序,可以提高效率。
6. 总结快速排序是一种非常实用的排序算法,其平均性能非常优秀。 理解不同的分区方案和优化策略,可以帮助你更好地应用快速排序算法。 选择合适的枢轴策略和处理小数组的方式对于算法的实际效率至关重要。