快速排序
算法概述
快速排序是在冒泡排序的基础上改进而来的,冒泡排序每次只能交换相邻的两个元素,而快速排序是跳跃式的交换,交换的距离很大,因此总的比较和交换次数少了很多,速度也快了不少。
快速排序的算法思想稍微有点复杂,但是还是比较容易理解的。
快速排序的思想就是挖坑填坑+分治法
比如下面这个数组,我们首先选择一个基准数,我们就选择第一个数作为基准数,然后我们要在这个数组里面找到一个坑,把72这个数填进去,使得72的左边全部都是比72小的数,72的右边全部都是比72大的数。
那现在我们开始来找这个坑。
首先我们定义int x=s[0]=72,i=0,j=9。
由于我们已经将s[0]中的数保存在了变量x中,那么就可以看做s[0]现在是一个坑,我们要找到一个数把这坑填上。
因为左边小右边大,所以我们要找的这个数肯定是比72小的数。
所以我们从j=9开始遍历,发现s[8]比x小,我们就把s[8]的数填到s[0]中。
接着s[8]就是我们新挖的坑了,我们要找到一个数把s[8]填上。我们从i=0开始遍历,找到了s[3]比x要大,我们把s[3]中的数填到s[8]中,如下图所示
接下来我们重复上面的过程,直到i>=j时,我们把72填入i的位置,这样72左边的数都大于72,72右边的数都小于72了
接下来再采用分治的思想,把0到4和6到9的数分别按照上面的方法排序,即可对整个数组完成排序。
这里我们之所以要维护i,j两个指针,有两个原因。
第一个原因是我们要保证前面的数永远都是小的,后面的数永远都是大的,所以我们用两个指针去交替遍历这个数组,在i的指针中遇到比x大的数,就让他填到后面的位置,在j的指针中遇到比x小的数,就让他填到前面的位置。
第二个原因是我们要找出基准数X的位置,通过两个指针的交替遍历,当两个指针相交的时候,就可以找到基准数X的位置,把他填入即可。
算法实现
void QUKsort(vector<int>& v,int f,int b)
{
if (f < b)
{
int x = v[f];
int i = f, j = b;
while (i < j)
{
while (i < j && v[j] >= x)
j--;
if (i < j)
v[i++] = v[j];
while (i < j && v[i] <= x)
i++;
if (i < j)
v[j--] = v[i];
}
v[i] = x;
QUKsort(v, f, i);
QUKsort(v, i + 1, b);
}
}
快速排序是在冒泡排序的基础上改进得来的,冒泡排序每一次只能交换两个相邻的数,而快速排序可以进行跨度很大的交换,因此提高了效率。
但是快速排序在最坏的情况下的时间复杂度和冒泡排序一样,都是O(n^2)
但是在平均情况下,快速排序的时间复杂度是O(nlogn),并且快速排序在大多数情况下,都要快于这个时间复杂度。
在同复杂度的排序算法下,快速排序的平均速度是最快的,所以这个算法被取名叫做快速排序