1 算法介绍
快速排序是一个“交换类”的排序,以军训排队为例,教官说:“第一个同学出列,其他人以他为中心,比他矮的全排到他的左边,比他高的全排他右边。”这就是一趟快速排序。可以看出,一趟快速排序是以一个“枢轴”为中心,将序列分成两部分,枢轴的一边全是比它小(或者小于等于)的,另一边全是比他大(或者大于等于)的。
2 执行流程
原始序列:
49 38 65 97 76 13 27 49
i j(i和j开始时分别指向头,尾元素)
进行第一趟快速排序,以第一个数49作为枢纽(通常都选第一个元素作为枢纽),整个过程是一个交替扫描和交换的过程。
1)使用j,从序列最右端开始向前扫描,直到遇到比枢轴49小的数27,j停在这里。
49 38 65 97 76 13 27 49
i j
2)将27交换到序列前端i的位置。
27 38 65 97 76 13 49
i j
3)使用i,交换扫描方向,从前向后扫描,直到遇到比较枢轴49大的数65,i停在这里。
27 38 65 97 76 13 49
i j
4)将65交换到序列后端j的位置。
27 38 97 76 13 65 49
i j
5)使用j,交换扫描方向,从后向前扫描,直到遇到比枢轴49小的数13,j停在这里。
27 38 97 76 13 65 49
i j
6)将13交换到i的位置。
27 38 13 97 76 65 49
i j
7)使用i,交换扫描方向,从前向后扫描,直到遇到比49大的数97,i停在这里。
27 38 13 97 76 65 49
i j
8)将97交换到j位置。
27 38 13 76 97 65 49
i j
9)使用j,交换扫描方向,直到遇到比49小的数,当扫描到i与j相遇时,说明扫描过程结束了。
27 38 13 76 97 65 49
ij
10)此时i等于j的这个位置就是枢轴49的最终位置,将49放入这个位置,第一趟快速排序结束。
27 38 13 49 76 97 65 49
ij
可以看出一次快速排序后,将原来的序列以49为枢轴,划分为两部分,49左边的数都小于或等于它,右边的数都大于或等于它。接下来按照同样的方法对序列{27 38 13}和序列{76 97 65 49}分别进行快速排序。经过几次这样的快速排序,最终得到一个有序的序列。
快速排序代码如下:
#include <iostream>
void QuickSort(int *arr, int l, int r)
{
int len = r; // 存储当前数组的最后一个元素的坐标
int num = arr[l]; // 用来存放枢轴元素
bool dir = 0; // 用来表示移动方向
/*一趟快速排序*/
while (l != r)
{
if (dir == 0)
{
if (arr[r] < num)
{
arr[l] = arr[r];
dir = 1;
}
else
{
r--;
}
}
else
{
if (arr[l] > num)
{
arr[r] = arr[l];
dir = 0;
}
else
{
l++;
}
}
}
arr[l] = num; // 将枢轴元素放入最终位置
if (l > 1)
{
QuickSort(arr, 0, l - 1);
}
if (len - l - 1 > 1)
{
QuickSort(arr, l + 1, len);
}
}
int main()
{
int arr[] = { 49, 38, 65, 97, 76, 13, 27, 49 };
int len = 8;
QuickSort(arr, 0, len - 1);
for (int i = 0; i < len; i++)
{
std::cout << arr[i] << " ";
}
std::cout << std::endl;
system("pause");
return 0;
}
简化后的快速排序算法实现代码:
void QuickSort(int *pArray, int iBegin, int iEnd)
{
if (iBegin < iEnd)
{
int iLeft = iBegin;
int iRight = iEnd;
int iPivot = pArray[iBegin];
while (iLeft < iRight)
{
while (iLeft < iRight && pArray[iRight] >= iPivot)
{
iRight--;
}
if(iLeft < iRight) pArray[iLeft++] = pArray[iRight];
while (iLeft < iRight && pArray[iLeft] <= iPivot)
{
iLeft++;
}
if(iLeft < iRight) pArray[iRight--] = pArray[iLeft];
}
pArray[iLeft] = iPivot;
QuickSort(pArray, iBegin, iLeft - 1);
QuickSort(pArray, iRight + 1, iEnd);
}
}
性能分析
(1)时间复杂度分析
快速排序最好情况下的时间复杂度为O(nlog2n),待排序列越接近无序,本算法效率越高。最坏情况下的时间复杂度为O(n2),待排序列越接近有序,本算法效率越低。平均时间复杂度为O(nlog2n)。就平均时间而言,快速排序是所有排序算法中最好的。快速排序的排序趟数与初始序列有关。
(2)空间复杂度分析
本算法空间复杂度为O(log2n)。快速排序是递归进行的,递归需要栈的辅助,因此它需要的辅助空间较多。