快速排序(三数取中法)源码

快速排序是一种最坏情况时间复杂度为Θ(n2)。虽然最坏情况时间复杂度很差,但是快速排序通常是实际排序应用中最好的选择,因为它的平均性能非常好:它的期望时间复杂度是Θ(nlgn),而且Θ(nlgn)中隐含的常数因子非常小。另外,它还能够进行原址排序。

1.快速排序的描述

快排也使用了分治的思想,对数组A[p..r]进行快速排序的三步分治过程如下:

分解:数组A[p..r]划分为两个(可能为空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中任意元素<=A[q],且A[q]<=A[q+1..r]中的每个元素。

解决:通过递归调用快排,对子数组A[p..q-1]和A[q+1..r]进行排序。

合并:因为子数组都是原址的,所以不需要合并操作:数组A[p..r]已经有序。

伪代码:

QuickSort(A, p,r)
if(p < r)
    q = Patition(A,p,r)
    QuickSort(A,p,q-1);
    QuickSort(A,q+1,r)

数组的划分

伪代码:(选择数组最后一个元素A[r]作为主元(pivot element),使用A[r]作为划分数组的标志)

Partition(A,p,r)
x=A[r]
i=p-1
for j=p to r-1
    if(A[j]<=x)
        i++
        exchange A[i] with A[j]
exchange A[i+1] with A[r]
return i++;

将主元与最左的大于x的元素进行交换,可以将主元移动到它在数组中的正确位置,并返回主元此时在数组中的下标。Partition的执行复杂度是Θ(n)。

2.快速排序的性能

快排的时间性能依赖于划分是否平衡,平衡与否又依赖于划分的元素。当划分是平衡的时候,快排的性能与归并排序一样,如果划分是不平衡的快排的性能接近于插入排序。
最坏情况下:
当划分产生的两个子问题分别包含n-1和0个元素时,快排最坏情况发生了。当每次都是最坏情况划分是T(n)=T(n-1)+Θ(n),T(n)=Θ(n2)。
最坏情况下快排的时间效率并不比插入排序号,此外当输入数据完全有序时,快排的时间复杂仍为Θ(n2),而在同样情况下插入排序的时间复杂度为O(n)。
最好情况下:
T(n)=2T(n/2)+Θ(n),T(n)=Θ(nlgn)。
平衡情况下:
快排平均运行时间更接近于最好情况而不是最坏情况。假设每次划分都是9:1,快排递归式是T(n)=T(9n/10)+T(n/10)+cn。数中每一层的代价都是cn,直到在深度log10N=Θ(lgn)达到递归边界,之后每一层代价至多为cn。因此快排的总代价为O(nlgn)。

3.快排的随机化版本

与始终采用A[r]作为主元不同,随机抽样从子数组中A[p..r]中随机选择一个元素作为主元。我们可以将A[r]与A[random]交换,然后对其进行划分。
本例采用三数取中法,从子数组中随机选出三个元素,取其中位数作为主元。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

template <typename T>
void fExchange(T &a, T &b)
{
	T temp = b;
	b = a;
	a = temp;
}

template<typename T>
void fQuickSort(T A[], int p, int r)
{
	if (p < r)
	{
		int q = fPartition(A, p, r);
		fQuickSort(A, p, q-1);
		fQuickSort(A, q + 1, r);
	}
}


template<typename T>
int fPartition(T A[], int p, int r)
{
	srand(unsigned(time(0)));//选种子seed

	int ran1 = (rand() % (r - p + 1)) + p;//产生[p,r]范围的随机数,取三个随机数的中间数
	int ran2 = (rand() % (r - p + 1)) + p;
	int ran3 = (rand() % (r - p + 1)) + p;
	int ran;

	if (A[ran1] >= A[ran2] && A[ran1] <= A[ran3])
		ran = ran1;
	else if (A[ran2] >= A[ran1] && A[ran2] <= A[ran3])
		ran = ran2;
	else
		ran = ran3;


	T x = A[ran];
	fExchange(A[ran], A[r]);//将随机选出的数与A[r]交换
	int i = p - 1;
	for (int j = p; j <= r-1; j++)
	{
		if (A[j] <= x)
		{
			i++;
			fExchange(A[i], A[j]);
		}
	}
	fExchange(A[i + 1], A[r]);//将x放在数组中的顺序位置
	for (int i = 0; i <= 11; i++)
		cout << A[i] << "  ";
	cout << endl;
	return i + 1;
	
}

void main()
{
	int A[12] = { 13, 19, 9, 5, 12, 8, 7, 4, 21, 2, 6, 11 };
	fQuickSort(A, 0, 11);
}




 


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值