分治法_随机快速排序

常规快速排序基本思想:

                分解-->递归求解

           以下是我认为最简洁的快速排序代码


void QuickSort(int a[],int p,int r)
{
	if(p<r)
	{
		int q=Partion(a,p,r);
		QuickSort(a,p,q-1);
		QuickSort(a,q+1,r);
	}
	
}

int Partion(int a[],int p,int r)
{
	int i=p,j=r+1;
	int x=a[p];
	while(true)
	{
		while(a[++i]<x&&i<r);//i没有等于r的原因,是为了避免重复比较
		while(a[--j]>x);
		if(i>=j) break;
		Swap(a[i],a[j]);
	}
	a[p]=a[j];		//至于为什么要交换a[j]和a[p]因为排序到了最后只剩下a[p]大于或者等于a[j](假如只有2,5此时a[p]=a[j]=2)所以必须要交换
	a[j]=x;
	PrintArray(a,9);
	return j;           //为什么选择j而不是i,因为到了i>j的情况时,a[i]肯定大于a[j],选择a[i]的话肯定会打乱排序的
}


红色数字表示分割数组的基准元素,左边小于它,右边大于它。

蓝色下划线表示将要进行排序的元素。


总所周知:快速排序的算法平均时间为O(nlogn),因为存在最差的情况O(n^2),这时间复杂度只是平均而已,具体到某个实例或许就不是这样了



为什么呢?


因为快速排序运行时间与划分是否对称有关,假如你的每次划分都不是很均匀,时间复杂度绝对不可能有O(nlogn),

例如(8,7,6,5,4,3,2,1,0),结果如图:


这里可以看出有8次递归,并没有>8log8=7.22,从输出可见,而且有些递归是没有意义的。

那么所谓的均匀划分又是什么呢?

在某一轮排序时,不是单一只选择首位做基准(如上述的常规算法),而是每次基准的选择都是随机的,对每个元素而言概率大致相同的。


int Partion(int a[],int p,int r)
{
	int i=p,j=r+1;
	<span style="color:#FF0000;">int k=Random(p,r);
	Swap(a[p],a[k]);</span>
	int x=a[p];
	while(true)
	{
                while(a[++i]<x&&i<r);  //i没有等于r的原因,是为了避免重复比较
		while(a[--j]>x);
		if(i>=j) break;
		Swap(a[i],a[j]);
	}
	a[p]=a[j];			//至于为什么要交换a[j]和a[p]因为排序到了最后只剩下a[p]大于或者等于a[j](假如只有2,5此时a[p]=a[j]=2)所以必须要交换
	a[j]=x;
	PrintArray(a,9);
	return j;           //为什么选择j而不是i,因为到了i>j的情况时,a[i]肯定大于a[j],选择a[i]的话肯定会打乱排序的
}


int Random(int a,int b)
{
	return (a+b)/2;
}

在这里我的随机生成数函数是简单的取中位数,但确实是有效果的,递归规模降低成了7次




然后当我优化一下随机数生成函数,效果更加明显,递归次数基本上4,5,6左右

int Random(int a,int b)
{
	srand((int)time(NULL));
	return (int)(rand()%(b-a+1)+a);
}





看看激动不,当时我就震惊了,时间复杂度竟然可以优化大O(n/2)啊,简直是超神了。


由此可见快速排序的时间复杂度和划分程度有很大关系,更重要的是随机选择策略的使用,会显著提高快排的速度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值