【算法导论】快速排序和随机化快速排序


title: Quicksort
date: 2023-10-2 18:18:49
tags: Computer science


快速排序和随机化快速排序

快速排序

描述

首先,我们介绍快速排序。快速排序与归并排序类似,基于分治的思想,将问题分解为子问题解决,再合并,但由于快速排序是不需要开辟临时变量的原址操作,因此不需要合并,详见以下说法。

分解

我们对数组array[left,…,right]进行操作,将其划分为三个部分:array[left,p-1],array[p+1,right],array[p]。所有的array[left,p-1]中所有的元素小于(大于)array[p],所有的array[p+1,right]的所有元素大于(小于)array[p]。

解决

通过递归调用快速排序,对子数组array[left,p-1]和array[p+1,right]进行排序。

此时array[left,right]已经有序。

代码

书上已经给出伪代码,下面给出java代码实现:

public static int Partition(int[] a,int left,int right){
	int x = array[right];
	int p = left - 1;
	if(array[i] <= x){
		int x = array[right];
		int p = left - 1;
        for(int i = left;i < right;i++){
            p++;
            swap(array,array[p],array[i]);
        }
	}
	swap(array,array[p+1],array[right])
	
	return p+1;
}

此部分代码对array[left,right]代码实现了原址重排。

下面给出图解:
在这里插入图片描述

忽略拙劣的画图技术,我们可以看到上面数列被分为了四个部分,表示比主元x小的部分,比x大的部分,未处理的部分,主元x,在图中r所指向的值就是主元x:

l<=xp>xi未处理

Partition维护了四个部分:在array[l,p]上的元素都不大于x,array[p+1,i]上的元素都大于x,array[i,r]上的元素未经处理。

那么对已经划分的数组的两部分分别进行递归调用:

public static void QuickSort(int[] array,int left,int right){
	if(left < right){
	int p = Partition(a,left,right);
	QuickSort(array,left,p-1);
	QuickSort(array,p+1,right);
	}
}

性能分析

Partition的时间复杂度为O(n),其中n = r - l + 1;QuickSort的时间复杂度取决于Partition的划分情况;

最坏情况

当划分产生的子问题的元素分别是n-1和0时,划分的最坏情况产生了。

假如每次的划分都是这种极不平衡的划分情况,已知Partition的的时间复杂度是O(n),当划分产生一个空元素的集合,调用直接返回,T(0) = O(1),其递归式可以表示为:

​ T(n) = T(n-1)+T(0)+O(n) = T(n-1)+O(n),

那么每一层的递归代价的累加和就是一个算术级数,即O(n^2).

最佳情况

当划分产生的子问题的元素都不大于n/2,划分的最佳情况诞生。

可以得到递归式为:

T(n) = 2T(n/2)+O(n).

由主定理(Master Theorem)得时间复杂度为O(nlgn);

平衡情况

平衡情况的划分的时间复杂度可以观察递归树得到:

比如某个问题的解决的递归式满足:

T(n) = T(9n/10)+T(n/10)+O(n)

递归树的节点是问题的规模,假如用常数c,令cn成为每一次递归的代价,每一次递归的代价至多为cn,当递归的深度为
l o g 10 / 9 n = O ( l g n ) log_{10/9}n = O(lgn) log10/9n=O(lgn)
,达到终止,因此总时间复杂度为O(nlgn).

可见,当一个划分产生一个0元素集合时,时间复杂度退化到O(n^2),为了避免这点,我们可以有了快速排序的随机化版本。

随机化快速排序

为了获得期望的划分情况,我们在选取划分的主元时可以随机选取array[left,right]的随机元素作为主元,我们仅需要对Partition进行修改:

public static int RandomPartition{
	r = random.nextint(right-left)+left;
	swap(array[right],array[r]);
	return Partition(a,left,right);
}

其余部分相同。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值