快速排序(Quick Sort)是对冒泡排序算法的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序算法是最流行的排序算法,也是速度最快的排序算法。
快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
- 首先设定一个分界值,通过该分界值将数组分成左右两部分;
- 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值;
- 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理;
- 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。
例如: 使用快速排序算法将数组 { 4,2,8,0,5,7,1,3,6,9 } 进行升序排序。
实现代码如下所示。
#include<iostream>
using namespace std;
template<class T>
void QuickSort(T *a, const int left, const int right)
{
if (left < right)
{
//选枢轴
int i = left;
int j = right + 1;
T pivot = a[left]; //pivot为枢轴,从数组左边开始
//进行划分
do {
do i++; while (a[i] < pivot); //找到比枢轴大的
do j--; while (a[j] > pivot); //找到比枢轴小的
if (i < j)
{
swap(a[i], a[j]); //小的放左边,大的放右边
}
} while (i < j);
swap(a[left], a[j]);
//递归
QuickSort(a, left, j - 1);
QuickSort(a, j + 1, right);
}
}
int main()
{
int a[] = { 4,2,8,0,5,7,1,3,6,9 };
cout << "排序前:" << endl;
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
cout << endl;
QuickSort(a, 0, 9);
cout << "排序后:" << endl;
for (int i = 0; i < 10; i++)
{
cout << a[i] << " ";
}
cout << endl;
double b[] = { 4.1,2.2,8.3,0.4,5.5,7.6,1.7,3.8,6.9,9.0 };
cout << "排序前:" << endl;
for (int i = 0; i < 10; i++)
{
cout << b[i] << " ";
}
cout << endl;
QuickSort(b, 0, 9);
cout << "排序后:" << endl;
for (int i = 0; i < 10; i++)
{
cout << b[i] << " ";
}
cout << endl;
system("pause");
return 0;
}
排序前:
4 2 8 0 5 7 1 3 6 9
排序后:
0 1 2 3 4 5 6 7 8 9
排序前:
4.1 2.2 8.3 0.4 5.5 7.6 1.7 3.8 6.9 9
排序后:
0.4 1.7 2.2 3.8 4.1 5.5 6.9 7.6 8.3 9
快速排序算法的详细过程如下图所示。
时间复杂度: 假设处理的数据规模大小为
n
n
n,运行时间设为
T
(
n
)
T(n)
T(n):
① 当把
n
n
n分为两半时,那么处理大小为
n
2
\frac{n}{2}
2n子数组花费时间为:
T
(
n
2
)
T(\frac{n}{2})
T(2n);
② 合并花费时间与数据规模成正比:
n
n
n。
所以处理规模大小为
n
n
n的数据所需要花费两个大小为
n
2
\frac{n}{2}
2n的子数组加上合并花费的时间,即
T
(
N
)
=
2
T
(
n
2
)
+
n
T(N) = 2T(\frac{n}{2}) + n
T(N)=2T(2n)+n。
对于
n
=
1
n = 1
n=1,
T
(
1
)
=
1
T(1) = 1
T(1)=1,求出
T
(
n
)
T(n)
T(n):
T
(
n
)
=
T
(
n
2
)
+
n
上
述
等
式
两
边
同
除
以
n
,
得
T
(
n
)
n
=
T
(
n
2
)
n
2
+
1
令
n
=
n
2
T
(
n
2
)
n
2
=
T
(
n
4
)
n
4
+
1
⋮
T
(
2
)
2
=
T
(
1
)
1
+
1
将
上
面
所
有
方
程
相
加
,
得
T
(
n
)
N
=
T
(
1
)
1
+
l
o
g
n
又
因
为
T
(
1
)
=
1
则
T
(
n
)
=
n
+
n
l
o
g
n
=
O
(
n
l
o
g
n
)
\begin{matrix} T\left ( n \right )=T\left ( \frac{n}{2} \right )+n \ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \\上述等式两边同除以n,得 \frac{T\left ( n \right )}{n}=\frac{T\left (\frac{n}{2}\right )}{\frac{n}{2}}+1\ _{}\ _{}\ _{} \\ 令n=\frac{n}{2}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \\\frac{T\left ( \frac{n}{2} \right )}{\frac{n}{2}}=\frac{T\left (\frac{n}{4}\right )}{\frac{n}{4}}+1\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \\ \vdots \ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \\\frac{T\left ( 2 \right )}{2}=\frac{T\left (1\right )}{1}+1\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \\将上面所有方程相加,得\frac{T\left ( n \right )}{N}=\frac{T\left (1\right )}{1}+logn\ _{} \\ 又因为T(1) = 1\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \\则T\left ( n \right )=n+nlogn=O(nlogn)\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{}\ _{} \end{matrix}
T(n)=T(2n)+n 上述等式两边同除以n,得nT(n)=2nT(2n)+1 令n=2n 2nT(2n)=4nT(4n)+1 ⋮ 2T(2)=1T(1)+1 将上面所有方程相加,得NT(n)=1T(1)+logn 又因为T(1)=1 则T(n)=n+nlogn=O(nlogn) 对于快速排序算法,最好的情况就是每次分割都能够从数组的中间分割,如上述所示的情况,这样分割
l
o
g
n
logn
logn次就行了,此时的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
但也有可能会出现一种极端的情况,每次分割的时候,主元左边的元素个数都为0,而右边都为
n
−
1
n-1
n−1个。这个时候,就需要分割
n
n
n次了。而每次分割整理的时间复杂度为
O
(
n
)
O(n)
O(n),所以最坏的时间复杂度为
O
(
n
2
)
O(n^{2})
O(n2)。
平均时间复杂度,则是假设每次主元等概率着落在数组的任意位置,最后算出来的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
空间复杂度: O ( n ) O(n) O(n)。
稳定性: 由于在排序的过程中,主元在和 j j j交换的时候是有可能破坏稳定性的,所以快速排序是不稳定的排序,如下图所示。