【数据结构】快速排序的深入分析

快速排序的时间复杂度

void Swap(int* a, int* b)
{
	int tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}
void QuickSort1(int* a, int left, int right)
{
	
	int begin = left;
	int end = right;
	int keyi = begin;
	if (begin >= end)
		return;
	while (left <right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left<right && a[left]<=a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	keyi = left;
	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi + 1, end);
}

 快速排序最坏情况

当序列有序时,快速排序时间复杂度最高为n方

如图片所示,当序列有序时二叉树没有左侧节点,只有右侧节点,高度为n,每层为n、n-1、

n-2……1,计算可得时间复杂度约为O(N^2)。

快排的一般情况

当序列无序时,快排的时间复杂度为O(N*logN)。

具体分析需要用到二叉树的内容,二叉树中完全二叉树的高度为log(N+1),每层时间复杂度约为N,所以整体的时间复杂度约为O(N*logN)。

本节重点是理解快排的最坏情况,为后面的优化做铺垫,一般情况,大家可以根据二叉树的内容还有快排的逻辑来推算。

快排的优化(如何避免最坏情况的出现)

随机数法

随机数法用到了rand()函数,头文件为<stdlib.h>

由于在最坏情况时,基准值的选取总是从最小的数开始选取,导致树的高度为n,因此我们随机选取基准值,然后将选取的基准值与left互换,其他操作不变。

其中有一些细节,right-left+1是为了防止数组越界,把randi控制在n中,randi+=left是为了将randi控制在left与right范围中。

void QuickSort1(int* a, int left, int right)
{
	if (left >=right)
		return;
	//随机数
	int randi = rand();
	//使随机数大小不超过n
	randi %= (right - left + 1);
	//保证随机数在left到right范围里
	randi += left;
	Swap(&a[randi], &a[left]);
	int begin = left;
	int end = right;
	int keyi = left;
	while (left <right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left<right && a[left]<=a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	keyi = left;
	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi + 1, end);
}

 三数取中法

具体思路:引入变量mid,将基准值选择在mid位置,mid的算法是(left+right)/2,这样也能避免最坏情况的出现。

int GetMid(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] < a[mid]) {
		if (a[mid] < a[right])
			return mid;
		else if (a[left] > a[right])
			return left;
		else return right;
	}
	else {
		if (a[mid] > a[right])
			return mid;
		else if (a[left] > a[right])
			return left;
		else return right;
	}
}
void QuickSort1(int* a, int left, int right)
{
	if (left >=right)
		return;
	int mid = GetMid(a,left,right);
	Swap(&a[mid], &a[left]);
	int begin = left;
	int end = right;
	int keyi = left;
	while (left <right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left<right && a[left]<=a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[keyi], &a[left]);
	keyi = left;
	QuickSort1(a, begin, keyi - 1);
	QuickSort1(a, keyi + 1, end);
}

快速排序的空间复杂度

快速排序Hoare版本的空间复杂度为O(logN)-O(N),一般情况为O(logN),最坏情况(序列有序时)为O(N)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值