快速排序(Quick Sort)
快速排序是利用分治法的分区交换排序。将待排数组分成两个子数组,再分别对这两个子数组递归地进行快排。该算法由C.A.R.Hoare于1962年发表在Computer Journal5第一期。
库函数
在C语言中<stdlib.h>
void qsort(void * base,size_t num,size_t size,
int(* compar)(const void *,const void *));//数组名(指向数组的第一个元素的指针),元素个数,元素大小(sizeof),比较函数的指针
在C++中<algorithm.>
std::sort
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
//比较函数可以省略 默认升序,
//这个函数实际为了避免递归过深,在分组小于16后使用堆排序或归并排序
算法分析
流程
- 若数组大小为0或1,返回
- 选择一个枢轴(privot),也可以叫:基准、基数、中间值……
- 将待排数组分为小于枢轴和大于枢轴的两个子数组
- 对子数组重复上述的过程(或利用栈迭代)
关键问题
- 如何选择中间值(privot)?
- 选择第一个元素
- 选择最后一个元素
- 选择中间元素
- 随机选择
选择第一个或最后一个基本相同。
-
如何分区(partition)?
-
利用额外空间,最后进行拼接
-
原地交换(in-place)
-
单向划分
-
双向划分
-
-
C++代码
单向划分原地交换 && 选择第一个元素作为privot,当数组为升序或所有元素相同,时间复杂度为O(n2)
//双向划分 && 最后一个元素作为privot && 原地交换
template<typename T>
void QuickSort(T arr[], int start, int end){
if(start >= end)
return;
int left = start;
int right = end - 1;
int privot = arr[end];
while(left < right){
while(arr[left] < privot && left<right) ++left;
while(arr[right] >= privot && left<right) --right;
std::swap(arr[left],arr[right]);
}
if(arr[left] > privot)//三种情况:1.没有小于privot的数,2.有小于也有大于,3.全都小于
std::swap(arr[left],arr[end]);
else
++left;
QuickSort(arr, start, left-1);
QuickSort(arr, left+1, end);
}
算法效率
随机顺序的数组
时间复杂度: O(nlogn)
空间复杂度:O(logn)栈空间,
有序数组
时间复杂度:O(n2)