快速排序两种写法的总结和探究

        做快排题目时,发现同是二分,基准数不同取法,会让相同数据的时间复杂度不同(好像理所应当),不过由于某些测试数据本身比较特殊,比如10000个自然数升序:(1,2,3,...,9997,9998,9999,10000)

我知道会有人说这不已经排好了吗,,,可事实是某平台测试数据就是如此。。。

将其输入后运用快排1:(耗时3.20s

//简化普通快排 
void qs_my(int l,int r)
{
	int i,j,t,temp;
	
	 if(l>r)// 
	 return;
	 
	 temp=a[l];//temp用于存储基准数
	 i=l;
	 j=r;
	 
	 while(i!=j)
	 {
	 	while(a[j]>=temp && i<j)j--;
	 	while(a[i]<=temp && i<j)i++;
	 	if(i!=j)
	 	{	t=a[i],a[i]=a[j],a[j]=t; }//交换 
     }
     
     a[l]=a[i];
     a[i]=temp;
     
     qs_my(l,i-1);
	 qs_my(i+1,r);
	  
} 

而利用快排2:竟然只用了28ms!整体上(五组数据)比sort函数还快了11ms!

void quickersort(int l,int r) 
{
	int mid = a[(l+r)/2];
	int i=l,j=r;
	do{
		while(a[i]<mid)i++;
		while(a[j]>mid)j--;
		if(i<=j){
			swap(a[i],a[j]);
			i++;
			j--;
		}
	} while(i<=j);
	if(l<j) quickersort(l,j);
	if(i<r) quickersort(i,r);
}

我仔细考量了一下后发现:

        快排本身时间复杂度在O(NlogN)~ O(N^2),结合测试数据,第一种代码由于取第一个数为基准数,对于正常升序每次需要遍历大于它的所有数一共n次,即1-n的等差数列,约是n*(n+1)/2,可视作O(N^2)的时间复杂度;对于第二种写法,每次遍历n-1次但分为两个等大的part,而次数每次减半,不妨设为k次,则要经历n=2^k(近似),取对数得k=logn(以2为底),乘积大约为n*logn,可视作O(N*logN)的时间复杂度;显然后者更底。

       但 此时我们还有一个疑惑:那么对于快排法1什么时候的数据的时间复杂度是O(NlogN)?

利用快排2的思想,我们不妨举个实例:(1..7)对于数据我们要让二等分的数放在每个part的首位,以便我们每次都能取到二等分的数。

则有序数列(1,2,...5,6,7)取如下混序时:

                                        ( 4 , 2 , 1 , 3 , 6 , 5 , 7 )

可以取到时间复杂度O(NlogN),对于一般情况,我们留给读者自证。(哈哈哈哈)

其实是这样的递推过程:

取有序数列N0(1,2,3,...,n-2,n-1,n)的中间一项M0=[(n-1)/2](取整函数),根据其所在位置将原数列左右分为两个part,我们不妨记为N1,N1',紧接着,对N1、N1'分别进行同样的操作(取中间元M1和M1'),最终递推到Nm数列有且仅有一个元素时停止,组成的新数列即为最佳混序列

可见,如果要想AC(bushi)还是要用些许技巧(doge)。

不过你要用STL的sort快排当我没说。

        当然;你要打表我更没话说。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值