概述
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。在平均状况下,排序n个元素要O(nlogn)次比较。在最坏状况下则需要O(n^2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(nlogn)算法更快,因为它的内部循环可以在大部分的架构上很有效率地被实现出来。
算法描述
1.先从元素序列中取一个数作为基准数。
2.将比这个基准数大的元素全放到它的右边,小于或者等于基准数的元素放到它的左边。这个称为分区(partition)操作。最终的结果就是元素序列分成了如下左右两个区间:
3.对左右区间递归的进行步骤1,2,直到各区间只有一个元素时结束递归操作,这时整个元素序列就已经完成排序了。
快速排序C/C++代码如下:
void Swap(int arr[], int i, int j)
{
int temp=arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 根据基准值调整数组为三个区域,返回基准值所在的位置
* @param arr
* @param left
* @param right
* @return 基准值所在的位置
*/
int AdjustArray(int arr[], int left, int right)
{
int left_index=left-1; //记录左区间最后一个元素的位置
int pivot = arr[right]; //选择最后一个数作为基准值
for (int i = left; i < right; i++) {
if (arr[i] <= pivot) {
Swap(arr, ++left_index, i); //将小于等于基准值的元素放到左区间末尾,剩下的就是大于基准值的元素自动排在右区间
}
}
Swap(arr, left_index + 1, right); //将基准值与右区间的第一个元素交换,该操作可能会把后面元素的稳定性打乱,所以快速排序是不稳定的算法。
return left_index + 1;
}
/**
* 快速排序
* 最差时间复杂度 当每次选取的基准都是最大或最小的元素,导致每次只划分出了一个分区,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2)
* 最优时间复杂度 每次选取的基准都是中位数,这样每次都均匀的划分出两个分区,只需要logN次划分就能结束递归,时间复杂度为O(nlogN)
* 平均时间复杂度 O(nlogn)
* 空间复杂度 主要是递归造成的栈空间的使用(用来保存left和right等局部变量),取决于递归树的深度,一般为O(logn),最差为O(n)
* 稳定性 不稳定
* @param arr
* @param left
* @param right
*/
void QuickSort(int arr[], int left, int right) {
if(left==right || left>right || left<0 || right <0)return;
int pivot_index = AdjustArray(arr, left, right); //调整基准值在元素序列中的位置
QuickSort(arr, left, pivot_index-1); //对左区间进行快速排序
QuickSort(arr, pivot_index + 1, right); //对右区间进行快速排序
}