快速排序优化(附上能检测排序算法的传送门)

总算通过了,快排。虽然可以用简单的sort解决(以前我就是),但是自己写呢?!有几个数据一直过不去,难道书上错了?

 显然是需要在基本快排上进行优化!!!

 建议大家可以去试下  快排测试,卡了我好久。。。

一、书上的普通快排

我们看看普通的快排(分析网上多的是,随便找一篇吧),以最后一个为基准,显然效率不是很稳定,最坏情况会退化到O(n^2)

用这种快排能只通过2个数据 我提交上去时间大该在 9640ms ........

/*快排一,显然期望时间是好的,但是数据会刁难*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 100050

void swap(int a[],int i,int j)
{
	int num=a[i];
	a[i]=a[j];
	a[j]=num;
}
void q_sort1(int a[],int l,int r)
{
	if(l>=r)
		return;
	int x=a[r];
	int i=l,min=l-1;
	while(i<r)
	{
		if(a[i]<=x)
		{
			swap(a,i,min+1);
			min++;  //比它小的数的个数 
		}
		i++;
	}
	min=min+1; //后面那位才是大于它的数 
	swap(a,min,r); //交换 
	q_sort1(a,l,min-1);
	q_sort1(a,min+1,r);
}
void show(int a[],int n)
{
	for(int i=0;i<n;i++)
	{
		printf("%d",a[i]);
		if(i!=n-1)
		printf(" ");
		else
			printf("\n");
	}
}
int a[Max];
int main()
{
	int a[]={1,0,5,9,8,7,6,3,0,4};
	int n=10;
//	int n;
//	scanf("%d",&n);
//	for(int i=0;i<n;i++)
//		scanf("%d",&a[i]);
	q_sort1(a,0,n-1);
	show(a,n);
	return 0;
}

二、随机化快排

我们很自然的想到了让快排随机,不错,情况比上面好点,能通过3组数据,但是数据还是刁难你。

其实只要你运气好,啥数据不能过,是吧。(手动狗头)

我提交这个数据,情况变好一点了,过了三组数据,但是时间是 6652ms......

/*添加随机数后的快排*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 100050
void swap(int a[],int i,int j)
{
	int num=a[i];
	a[i]=a[j];
	a[j]=num;
}
void q_sort1(int a[],int l,int r)
{
	if(l>=r)
		return;
	/*我们添加随机数    */
	int num = rand()%(r-l+1)+l;
	int x=a[num];
	a[num]=a[r];
	a[r]=x;
	/* -------- */
	x=a[r];
	int i=l,min=l-1;
	while(i<r)
	{
		if(a[i]<=x)
		{
			swap(a,i,min+1);
			min++;  //比它小的数的个数 
		}
		i++;
	}
	min=min+1; //后面那位才是大于它的数 
	swap(a,min,r); //交换 
	q_sort1(a,l,min-1);
	q_sort1(a,min+1,r);
}
void show(int a[],int n)  //输出
{
	for(int i=0;i<n;i++)
	{
		printf("%d",a[i]);
		if(i!=n-1)
		printf(" ");
		else
			printf("\n");
	}
}
int a[Max];
int main()
{
//	int a[]={1,0,5,9,8,7,6,3,0,4};
//	int n=10;
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
	q_sort1(a,0,n-1);
	show(a,n);
	return 0;
}

三、快排优化折磨区域

(一)、两边同时查找最大元素,最小元素,然后交换,减少循环的次数。

原本的快排每次只找一个数,然后判断是否交换,我们可以先找到一个大于基准的数,然后找到一个小于基准的数,然后交换他们两个,我也感觉快些(我没去证明.......)。

方法是不错啊,但是还是只能通过三组数据,时间是: 6526ms.......(快了一点呢,┭┮﹏┭┮)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 100050
void swap(int a[],int i,int j)
{
	int num=a[i];
	a[i]=a[j];
	a[j]=num;
}
void q_sort1(int a[],int l,int r)
{
	if(l>=r)
		return;
	/*我们添加随机数    */
	int num = rand()%(r-l+1)+l;
	int x=a[num];  //基准 
	a[num]=a[r];
	a[r]=x;
	/* -------- */
	int i=l,j=r;
	/*注意是先把最后一个覆盖,然后再交换,用覆盖来代替*/
	while(i<j)
	{
		while(i<j&&a[i]<=x)
		{
			i++;
		}
		a[j]=a[i];//第一个大于基准的数会覆盖最后一个,就是我们的基准 
		while(i<j&&a[j]>x)
		{
			j--;
		}
		a[i]=a[j];
		// 覆盖后 总是有个位置是多余的,因为我们把基准位置拿出来用了 
	}
	a[i]=x;  //基准归位 ,第i个位置就是我们基准的位置 
	q_sort1(a,l,i-1);
	q_sort1(a,i+1,r);
}
void show(int a[],int n)
{
	for(int i=0;i<n;i++)
	{
		printf("%d",a[i]);
		if(i!=n-1)
		printf(" ");
		else
			printf("\n");
	}
}
int a[Max];
int main()
{
//	int a[]={1,0,5,9,8,7,6,3,0,4};
//	int n=10;
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);
	q_sort1(a,0,n-1);
	show(a,n);
	return 0;
}

(二)、下面的我就只写思路了,因为这些方法还是都没过。(尴尬)

  1、当数据较小的时候(网上看的大概15个数),我们可以用插入排序代替快排,效率还会快些。

我们来看时间   6517ms(我只加了判断数据大小和插入排序),貌似又好了一点。

2、我们为什么要依靠随机选基准呢,所以用三分法优化快排,在需要排序的数据选三个数 (第一个数,中间一个数,最后一个数),然后选则三个数的中间值作为基准。(不怕告诉你,倒数第二组数据是从100000开始,逆序的,中间还有若干个重复的50000,貌似对这组数据很棒呢),结果是   6540ms   (更尴尬了.....),而且倒数第二组数据还没过。

3、难道是重复元素多了,导致不能ac, 然后我自己想了个算法,如果元素和基准相同都放到最后面,然后记录有多少个相同的元素,最后一起换过去。(显然我这算法结果不乐观,好像也是6600多ms),但是后面我会发现,思路没错,算法太low 了。......

应该对这倒数第二组数据友好啊??,后来我感觉可能是在选中间值的时候,判断次数太多了,反而造成时间过长?(需要分析,证明,上课无聊 再去偷偷证明,哈哈)还是的确优化了,但是还是不能通过,因为我们只能看到最后超时的结果,而且下载不了最后一组数据,我的电脑跑倒数第二组数据会栈溢出......。

 

四、AC区

 

(一)、并归和堆排序

    我测试了下并归排序和堆排序,结果 都过了,有点惊讶,我记得快排是比他们两个快的,所以问题再在,这题就是要测试你的快排,找的都是针对快排的数据。时间 分别事 127ms137ms  它摧毁的是一个好学者对快排的信心(可以用sort一遍过,才发现那些写STL多厉害,一样的快排到我手里就这么不争气,好吧是我不争气......)

(二)、三路划分的快排

  其实经过折磨区,我知道一些情况会对排序影响,当元素是逆序的情况、重复元素多的情况,Mcllroy[248]说明了如果设计杀手级对手,让快排的几乎所有运算都是Θ(n^2)(魔鬼...)

这次可以AC,其实思路就是把大于基准,等于基准,小于基准的分块放,然后就是简洁,不做多余的事(这也就是为什么我前面想到类似的方法,却没AC.......)  这次的时间:152ms    总算是 AC了,嘿嘿。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Max 100010
#define max(a,b) a>b?a:b;
#define min(a,b) a>b?b:a;
#define exchange(one,two) {int c=one;one=two;two=c;};
/*
void exchange(int &one,int &two)
{int c=one;one=two;two=c;}  //会报错... 
*/
void insert_sort(int a[],int low,int end)//开始位置到结束位置
{
	for(int i=low+1;i<=end;i++)
	{
		int num=a[i];
		int j=i;
		while(j>low&&num<=a[j-1])  //从后面往前面换 
		{
			exchange(a[j],a[j-1]);
			j--;
		}
	}
}
int partition(int a[],int p,int r)
{
	int x;  
	/*one*/ 
//	int num=(rand()%(r-p+1)+p);  //随机化 
//	exchange(a[num],a[r]);
//	x=a[r];//选择基准
//	int i=p;
//	for(int j=p;j<r;j++) //最后一个不需要换 
//	{
//		if(a[j]<=x)
//		{
//			exchange(a[j],a[i]);
//			i++;
//		}
//	 } 
//	exchange(a[i],a[r]);
//	return i; 


	/*two*/ 
//	int num=(rand()%(r-p+1)+p);  //随机化 
//	exchange(a[num],a[r]);
//	x=a[r];//选择基准
//	int i=p,j=r;//边界范围 
//	while(i<j)
//	{
//		while(i<j&&a[i]<=x) //从前面开始找找,大于基准的数 
//		{
//			i++;
//		}
//		exchange(a[i],a[j]);
//		while(i<j&&a[j]>x) //从后面 
//		{
//			j--; 
//		}
//		exchange(a[i],a[j]);
//	}
//	a[i]=x;
//	return i;
}
void quick_sort(int a[],int begin,int end)
{
	
	if(begin<end)
	{
		if(end-begin<=15)
		{
			insert_sort(a,begin,end);
			return;
		}
		int q=partition(a,begin,end);
		quick_sort(a,begin,q-1);
		quick_sort(a,q+1,end);
	}
}
void quick_sort_3(int a[],int p,int r)
{
//	if(r-p<=15)
//	{
//		insert_sort(a,p,r);
//		return;
//	}
	if(p>=r)
		return ;
	int x;
	int num=(rand()%(r-p+1)+p);  //随机化 
	exchange(a[num],a[r]);
	x=a[r];//选择基准
	int left=p-1,right=r+1,i=r-1; //最后一个是基准 
	while(i>left)
	{
		if(a[i]<x)  //小于的数放前面 
		{
			exchange(a[left+1],a[i]);
			left++;
		}
		else if(a[i]>x) //大于的数放后面 
		{
			exchange(a[right-1],a[i]);
			i--;
			right--;
		}
		else  //中空区市等于基准的数 
		{
			i--;
		}
	 }
	quick_sort_3(a,p,left);
	quick_sort_3(a,right,r);
}
void show(int a[],int n)
{
	for(int i=0;i<n;i++)
	{
		printf("%d",a[i]);
		if(i!=n-1)
		printf(" ");
		else
		printf("\n");
	}
}
int a[Max];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	quick_sort_3(a,0,n-1);
//	int b[]={1,0,9,8,5,6,7,4,3,2};
//	n=10;
//	show(b,n);
//	quick_sort_3(b,0,n-1);
//	show(b,n);
	show(a,n);
	return 0;
}

如果看我的三路分法没看明白,看这篇吧。

总算是把快速排序解决了,算法路子走的有点难,还有半年加油!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值