快速排序算法

  快速排序(Quick Sort)是对冒泡排序算法的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

  快速排序算法是最流行的排序算法,也是速度最快的排序算法。

  快速排序算法通过多次比较和交换来实现排序,其排序流程如下:

  1. 首先设定一个分界值,通过该分界值将数组分成左右两部分;
  2. 将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值;
  3. 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理;
  4. 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

  例如: 使用快速排序算法将数组 { 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                                     nnT(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 n1个。这个时候,就需要分割 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交换的时候是有可能破坏稳定性的,所以快速排序是不稳定的排序,如下图所示。

在这里插入图片描述

  • 6
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值