快速排序/三路快排

在这里插入图片描述
快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序n个元素要O(nlogn)次比较。在最坏状况下则需要O(n^2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他O(nlogn)算法更快,因为它的内部循环可以在大部分的架构上很有效率地被实现出来。

快速排序使用分治策略(Divide and Conquer)来把一个序列分为两个子序列。步骤为:

  • 从序列中挑出一个元素,作为”基准”(pivot).
  • 把所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准的后面(相同的数可以到任一边),这个称为分区(partition)操作。
  • 对每个分区递归地进行步骤1~2,递归的结束条件是序列的大小是0或1,这时整体已经被排好序了。

快排特点如下:

  • 分类 ------------ 内部比较排序
  • 数据结构 --------- 数组
  • 最差时间复杂度 ---- 每次选取的基准都是最大(或最小)的元素,导致每次只划分出了一个分区,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2)
  • 最优时间复杂度 ---- 每次选取的基准都是中位数,这样每次都均匀的划分出两个分区,只需要logn次划分就能结束递归,时间复杂度为O(nlogn)
  • 平均时间复杂度 ---- O(nlogn)
  • 所需辅助空间 ------ 主要是递归造成的栈空间的使用(用来保存left和right等局部变量),取决于递归树的深度,一般为O(logn),最差为O(n)
  • 稳定性 ---------- 不稳定

经典快排代码如下:

//bound指向<=x的下一位置 ,也就是>x的前一个位置
int partation1(int arr[], int l, int r)
{
	int bound = l;
	//以数组最后一个数arr[r]作为基准来分界
	for (int i = l; i < r;++i)
	{
		if (arr[i]>arr[r])
		{
			continue;
		}
		else swap(arr[bound++],arr[i]);
	}
//快速排序是不稳定的排序算法,不稳定发生下面这个swap函数处。
//比如序列:{ 1, 3, 4, 2, 8, 9, 8, 7, 5 },基准元素是5,一次划分操作后5要和第一个8进行交换,从而改变了两个元素8的相对次序。
	swap(arr[r], arr[bound]); 
	return bound;
}
void _quicksort1(int arr[], int l, int r)
{
	if (l >= r)
		return;
	int bound=partation1(arr, l, r);
	_quicksort1(arr, l, bound-1);
	_quicksort1(arr, bound + 1, r);
}

上述二路快排将数组分为两部分,一部分小于等于x,一部分大于x。如果将数组分为3部分,一部分小于x,一部分等于x,一部分大于x,则效率更高。

三路快排代码如下:

// lef指向下一个<x的数该放的位置,rig指向下一个>x的数该放的位置
vector<int>partation2(int arr[], int l, int r)
{
	int rig = r-1,lef=l;
 //注意边界条件,什么时候停止遍历  必须把所有数都遍历到,一个不能多,一个不能少
	while (l<=rig) 
	{
		if (arr[l]>arr[r])
		{
			swap(arr[rig--], arr[l]);
		}
		else if (arr[l] < arr[r])
		{
			swap(arr[lef++],arr[l++]);
		}
		else ++l;
	}
	swap(arr[r],arr[++rig]);
	//返回的是等于x的数在数组中的范围
	vector<int>res(2, 0);
	res[0] = lef;
	res[1] = rig;
	return res;
}
void _quicksort2(int arr[], int l, int r)
{
	if (l >= r)
		return;
	vector<int>bound = partation2(arr, l, r);
	_quicksort2(arr, l, bound[0] - 1);
	_quicksort2(arr, bound[1] + 1, r);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值