由于冒泡算法算法之路--冒泡算法(算法之路--冒泡算法)每轮都要进行从头到落位之前的每个元素的比较,在执行效率上需要提升,快速排序算法就是对冒泡算法的一种效率上的提升。
算法思路
快速排序是基于冒泡的改进,所以基本法则还是交换的方法,只是在交换的次数和方法上得到了提升。具体方法:
a.首先在数组中选中一个数值为参照数,一般我的习惯是选用第一个元素即可
b.对整个数组中大于这个数的数都交换到它的位置右边,比这个数小的数都交换到它的左边。从最后一个元素位置出发,当出现参照数小的数时,交换两者的数值。然后从最左侧出发,当出现参照数大的数时,交换两者数值。
c.采用分治的思想,对完成一次交换后的左边区间和右边区间分别再进行步骤a-c
第一轮交换:
参照数 | ←哨兵 | ||||
step1,5>2不用交换 | 2 | 4 | 1 | 3 | 5 |
step2,3>2不用交换 | 2 | 4 | 1 | 3 | 5 |
step3-1,1<2交换 | 2 | 4 | 1 | 3 | 5 |
step3-2 进行交换 | 1 | 4 | 2 | 3 | 5 |
step4 发现右侧都交换完,进行左侧的哨兵向右比较,4>2交换 | 1 | 2 | 4 | 3 | 5 |
第二轮交换:
左侧参照数发现右侧无可比较数,完成 | 1 | 2 |
右侧以4为参照数,5为哨兵,5>4不用交换,哨兵左移 | 4 | 3 | 5 |
3为哨兵,3<4需要交换 | 4 | 3 | 5 |
右侧也再无可交换元素 | 3 | 4 | 5 |
第三轮交换:
第三轮只需要进行右侧的比较即可
发现右侧均大于自己,且无左侧元素,且后面元素均完成了比较,即完成所有排序 | 3 | 4 | 5 |
3 | 4 | 5 |
上述图示中,红色代表参照数,绿色为哨兵位置,即比较位置,蓝色为完成比较的位置。
C++示例代码
#include <iostream>
#include <vector>
using namespace std;
void quickSort(vector<int>& v, int l, int r)
{
if (l >= r)
{
return;
}
int i = l;
int j = r;
int ref = v[l];
while (i < j)
{
while ((i < j) && (v[j] >= ref))
{
j--;
}
if (i < j)
{
swap(v[i], v[j]);
}
while ((i < j) && (v[i] < ref))
{
i++;
}
if (i < j)
{
swap(v[i], v[j]);
}
}
quickSort(v, l, i - 1);
quickSort(v, i + 1, r);
}
int main()
{
vector<int> vec{4,2,11,1,5,65,88,43,12,3,4};
quickSort(vec, 0, vec.size()-1);
system("pause");
return 0;
}
快速排序的性能
快速排序的运行时间依赖于划分是否平衡,而平衡与否又依赖于用于划分的元素,如果划分是平衡的,那么快速排序性能与归并排序一样,如果划分的是不平衡的,那么快速排序的性能就接近于插入排序。
最坏情况划分:当划分产生的两个左右子区间分别包含了n-1个元素和0个元素,即每次都要进行一次最长路径的比对,这时候的复杂度为O(n²)。
平均情况划分,即两边分别有(n-1)/2个元素,这时候的复杂度即O(nlogn)
空间复杂度由于是使用了交换的方法,不额外开辟空间,即复杂度为O(1)