在本教程中,您将学习快速排序的工作原理。另外,您还将找到使用C语言的示例。
Quicksort是一种基于分治方法的算法,它将数组分割成子数组,并递归调用这些子数组对元素进行排序。
快速排序算法如何工作?
-
从数组中选择轴心元素。可以从数组中选择任何元素作为轴心元素。
在这里,我们把数组最右边(即最后一个元素)作为轴心元素。
-
小于轴心元素的元素放在左侧,大于轴心元素的元素放在右侧。
通过以下步骤实现上述安排。
a. 指针固定在轴心元素上。轴心元素与第一个索引指示的元素进行比较。如果该元素大于轴心元素,则将第二个指针指向该元素。
b. 现在,轴心元素与其他元素(第三个指针)进行比较。如果当前元素小于轴心元素,则将较小的元素与先前找到的较大元素交换。
c. 这个过程一直持续到最后一个元素。
最后,轴心元素与第二个指针交换。
d. 现在,这个轴心元素的左、右两个子部分将在下面的步骤中进行进一步处理。 -
再次分别为左侧和右侧子部分选择轴心元素。在这些子部分中,轴心元素放置在正确的位置。然后,重复步骤2。
-
子部分再次被划分为更小的子部分,直到每个子部分由单个元素构成。
-
此时,数组已经排序。
快速排序使用递归对子部分进行排序
在分治法的基础上,快速排序算法可以解释为:
- 划分
以轴心为划分点,将数组划分为若干个子部分。小于轴心的元素放置在轴心的左侧,大于轴心的元素放置在轴心的右侧。 - 控制
通过为左、右子部分选择轴心元素,再次对其进行分治。这可以通过递归地将子部分传递给算法中来实现。 - 组合
此步骤在快速排序中不起重要作用。阵列已经在控制步骤结束时排序。
借助下面的插图,您可以理解快速排序的工作原理。
使用递归对轴心元素左边的元素进行排序
使用递归对轴心元素右侧的元素进行排序
快速排序算法伪代码
quickSort(array, leftmostIndex, rightmostIndex)
if (leftmostIndex < rightmostIndex)
pivotIndex <- partition(array,leftmostIndex, rightmostIndex)
quickSort(array, leftmostIndex, pivotIndex)
quickSort(array, pivotIndex + 1, rightmostIndex)
partition(array, leftmostIndex, rightmostIndex)
set rightmostIndex as pivotIndex
storeIndex <- leftmostIndex - 1
for i <- leftmostIndex + 1 to rightmostIndex
if element[i] < pivotElement
swap element[i] and element[storeIndex]
storeIndex++
swap pivotElement and element[storeIndex+1]
return storeIndex + 1
C示例
// Quick sort in C
#include <stdio.h>
// Function to swap position of elements
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
// Function to partition the array on the basis of pivot element
int partition(int array[], int low, int high) {
// Select the pivot element
int pivot = array[high];
int i = (low - 1);
// Put the elements smaller than pivot on the left
// and greater than pivot on the right of pivot
for (int j = low; j < high; j++) {
if (array[j] <= pivot) {
i++;
swap(&array[i], &array[j]);
}
}
swap(&array[i + 1], &array[high]);
return (i + 1);
}
void quickSort(int array[], int low, int high) {
if (low < high) {
// Select pivot position and put all the elements smaller
// than pivot on left and greater than pivot on right
int pi = partition(array, low, high);
// Sort the elements on the left of pivot
quickSort(array, low, pi - 1);
// Sort the elements on the right of pivot
quickSort(array, pi + 1, high);
}
}
// Function to print eklements of an array
void printArray(int array[], int size) {
for (int i = 0; i < size; ++i) {
printf("%d ", array[i]);
}
printf("\n");
}
// Driver code
int main() {
int data[] = {
8, 7, 2, 1, 0, 9, 6};
int n = sizeof(data) / sizeof(data[0]);
quickSort(data, 0, n - 1);
printf("Sorted array in ascending order: \n");
printArray(data, n);
}
快速排序的复杂度
时间复杂度
- 最坏情况复杂度[Big-O]:O( n 2 n^2 n2)
当选取的轴心元素是最大或最小的元素时发生。
这种情况导致轴心元素位于排序数组的最末端。一个子数组总是空的,另一个子数组包含 n-1 个元素。因此,仅对该子数组调用快速排序。
然而,对于散乱的轴心,快速排序算法有更好的性能。 - 最佳情况复杂度[大Ω]:O(n*log n)
当轴心元素始终是中间元素或靠近中间元素时为最佳情况复杂度。 - 平均情况复杂度[大θ]:O(n*logn)
当上述两种情况不发生时,为平均情况复杂度。
空间复杂度
quicksort的空间复杂度为O(log n)。
快速排序算法的应用
当出现以下情况时,使用快速排序算法:
- 编程语言有利于递归
- 时间复杂度很重要
- 空间复杂度很重要
参考文档
[1]Parewa Labs Pvt. Ltd.Quicksort Algorithm[EB/OL].https://www.programiz.com/dsa/quick-sort,2020-01-01.