小白学算法2.6——快速排序
标签: 小白学算法
1.快速排序算法
快速排序属于高级排序,时间复杂度为 O ( N l o g N ) O(NlogN) O(NlogN),空间复杂度 O ( l o g N ) O(logN) O(logN)~ O ( N ) O(N) O(N)。快速排序是最快的通用排序算法。
快速排序首先是选取数组中某个元素作为标准元素(一般是最左边的元素或者中间的元素),然后把小于这个元素的元素放置在数组的左边,把大于这个元素的元素放置在数组的右边,最后把左边和右边的交界处的元素和标准元素位置互换。这样的话,标准元素左边的元素都小于标准元素;标准元素右边的元素都大于标准元素,而标准元素处于最终排序结束后所在的位置。重复这一过程,直到被切分的子数组长度为1时停止。
快速排序采用的也是分治的思想,可以和归并排序做一下比较:
- 归并排序将数组分成两个子数组,这两个子数组有序后再有序合并,就可以得到原数组有序化以后的数组;快速排序也是将数组分成两个子数组,不过这两个数组有一个关系,那就是其中一个数组的任意元素都小于另一个数组的任意元素,将这两个数组有序后直接拼接,就可以得到原数组有序化以后的数组。
- 归并排序的递归在处理整个数组之前;快排的递归在处理整个数组之后
- 归并排序中数组被等分;快排中数组一般不是等分,取决于数组本身的内容
2.快速排序实现
void quickSort(int* a, int lo, int hi)
{
if (hi <= lo) return;
int i = lo, j = hi+1;
int v = a[lo];//标准元素
while(1)
{
while(a[++i] < v) if (i == hi) break;//从左向右找第一个不小于v的元素
while(a[--j] > v) ;//从右向左找第一个不大于v元素
if (i >= j) break;//如果所有元素已经按照左小右大排在v的左右两侧,结束本次循环
swap(a, i, j);//交换左边不小于v的元素和右边不大于v的元素的位置
}
swap(a, lo, j);//标准元素放到中间
quickSort(a, lo, j-1);
quickSort(a, j+1, hi);
}
if (i == hi) break;
表示所有元素都小于v
,之所以不检测j
是因为标准元素在最左边,它本身一定不大于它本身- 快排的关键在于切分的过程,即
Line5~Line14
。该过程使得数组满足以下条件:- 对于某个
j
,a[j]
已经处于最终排序后的位置 a[lo]
到a[j-1]
都不大于a[j]
a[j+1]
到a[hi]
都不小于a[j]
- 对于某个
- 快排的部分内容如下,灰色表示本次排序位置已经ok的,黄色表示交换的元素,红色标准元素:
3.总结
- 快速排序是最快的通用排序算法,因为其内循环指令少,且能高效的利用缓存
- 实际应用中的快速排序往往在开始之前会把待排序的数组元素随机化打乱,这样可以有效防止遇到最坏的排序情况
- 快速排序是不稳定排序,如果对稳定性有要求,往往使用归并排序
- 快速排序还可以改进,比如切分后子数组元素较少时,可以使用插入排序。将
if (hi <= lo) return;
改写为if (hi <= lo + M) insertSort(int* a, hi-lo+1);
即可