原理:
快速排序(Quick Sort)是一种高效的排序算法,它基于“分治法”(Divide and Conquer)的思想。快速排序通过将待排序的数组分成较小的子数组,然后递归地对子数组进行排序,最终将它们合并成有序的数组。
步骤概括如下:
-
选择基准元素: 从待排序的数组中选择一个元素作为基准元素。通常选择数组的第一个元素作为基准元素,但也可以选择最后一个元素或者随机选择一个元素作为基准元素。
-
划分操作: 将数组中的元素分为两部分,使得左边的元素都小于或等于基准元素,右边的元素都大于或等于基准元素。这个过程称为划分(Partition)操作。划分的目的是将前面选定的基准元素放在它最终应该出现的位置上。
-
递归排序: 对划分后的两个子数组分别进行快速排序。递归地重复以上步骤,直到每个子数组只包含一个元素,此时整个数组已经有序。
-
合并结果: 将排序后的子数组合并成一个有序的数组。
示例:
假设一个待排序数组:[5, 2, 9, 3, 7, 1, 8, 4]
-
选择基准元素:这里选择第一个元素5作为基准。
-
划分操作:将数组划分为[2, 3, 1, 4](小于5的部分)和[9, 7, 8](大于5的部分),基准元素5现在在正确的位置上。
-
递归排序:对划分后的两个子数组进行快速排序。
- 对[2, 3, 1, 4]进行快速排序,选择基准元素2,划分为[1]和[3, 4],再对子数组[3, 4]进行快速排序,最终得到[1, 2, 3, 4]。
- 对[9, 7, 8]进行快速排序,选择基准元素9,划分为[7, 8],再对子数组[7, 8]进行快速排序,最终得到[7, 8, 9]。
-
合并结果:将排序后的子数组合并为最终的有序数组[1, 2, 3, 4, 5, 7, 8, 9]。
C++代码实现快速排序:
#include <iostream>
using namespace std;
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int left = l, right = r;
int temp = q[left];
while (left < right)
{
while (q[right] >= temp && left < right) {
right--;
}
if (left < right) {
q[left] = q[right];
left++;
}
while (q[left] < temp && left < right) {
left++;
}
if (left < right) {
q[right] = q[left];
right--;
}
}
q[left] = temp;
quick_sort(q, l, left-1);
quick_sort(q, left + 1, r);
}
int main()
{
int arr[] = { 2,4,1,3,6,9,7,5 };
cout << "排序前:" << endl;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
cout << arr[i] << " ";
}
cout << endl;
int a = 0, b = sizeof(arr) / sizeof(arr[0]) - 1;
quick_sort(arr, a, b);
cout << "排序后:" << endl;
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
cout << arr[i] << " ";
}
return 0;
}
运行结果截图:
时间复杂度:
快速排序的时间复杂度主要取决于两个因素:划分操作和递归调用。
-
划分操作: 在划分操作中,我们需要对数组进行遍历以找到基准元素的正确位置。在最坏情况下,数组已经有序或基本有序时,每次划分可能只减少一个元素的区间大小,导致划分过程变得非常慢。因此,最坏情况下的划分操作的时间复杂度为O(n),其中n是待排序数组的元素个数。
-
递归调用: 在每次递归调用时,问题规模减少一半,即处理的子数组大小为原数组的一半。递归调用的次数取决于数组的划分情况,最坏情况下需要进行O(n)次递归调用。
由于快速排序是一个递归算法,我们需要考虑所有递归调用的时间复杂度。因此,快速排序的平均时间复杂度为O(nlogn),最坏情况下为O(n^2)。
最坏情况:
原本需要排序的数组已经有序,如果使用快速排序算法,则时间复杂度直接退化为O(n^2)。
空间复杂度:
快速排序的空间复杂度主要取决于递归调用过程中的栈空间。在最坏情况下,递归调用可能会达到O(n)层,每层需要O(1)的空间来存储局部变量。因此,在最坏情况下,快速排序的空间复杂度为O(n)。
需要注意的是,快速排序通常是一个原地排序算法,它不需要额外的存储空间来存储临时数据。但由于递归调用过程中需要使用栈空间,所以在最坏情况下,空间复杂度为O(n)。
综上所述,该快速排序算法的平均时间复杂度为O(nlogn),最坏情况下的时间复杂度为O(n^2),而空间复杂度为O(n)。