第二周(快速排序)

快速排序的大致思路

通过找出一个基准数,然后从左向右,从右向左依次找出比这个基准数大(小)的数字,然后交换它俩
最后将基准数与每轮判断的结尾处交换,
这样每轮结束后,刚刚排序的部分都会被分成两部分,在基准数左边的数字都比基准数小,在基准数右边的数字都比基准数大
然后不断二分下去,最后整体排序完成 ,此方法主要运用了递归二分
好像貌似说的有点抽象

时间复杂度

快速排序的最差时间复杂度是O(n2)
它的平均时间复杂度为O(nlogn)


下面来段正确代码

#include<stdio.h> 
int n,a[100000];	//定义为全局变量在要用时就比较方便
void quicksort(int left,int right)//传参每次传进来左边与右边的边界值即可
{
 	int temp,i,j,flag;
 	if(left>right)	
 		return;
 	temp=a[left];	//每次的temp中存入的就是基准数
 	i=left;	
 	j=right;
 	while(i!=j)	//当i==j时,说明关于基准数的左右两边已经判断完了
 	{
  		while(a[j]>=temp&&i<j)	//当a[j]大于基准数时,就跳过它
   			j--;//当a[j]小于基准数时,就退出循环,
   			    //确定了右边需要交换的位置
  		while(a[i]<=temp&&i<j)//当a[j]小于基准数时,就跳过它
   			i++;//当a[j]大于基准数时,就退出循环,
   				//确定左边需要交换的位置
  		if(i<j)	//确定是基准数的左右边
  		{
   			flag=a[i];
   			a[i]=a[j];
   			a[j]=flag;
  		}
 	}
 	a[left]=a[i];	//将基准数归位,此时基准数左边的比基准数小
 			//基准数右边的,比基准数大
 	a[i]=temp;
 	quicksort(left,i-1);	//递归,不断处理基准数左边的部分
 	quicksort(i+1,right);	//递归,不断处理基准数右边的部分
}
int main()
{
 	int i;
 	scanf("%d",&n);
 	for(i=1;i<=n;i++)
  		scanf("%d",&a[i]);
 	quicksort(1,n);
 	for(i=1;i<=n;i++)
  		printf("%d ",a[i]);
 	return 0;
}

好的,现在到了最爱的举个栗子环节
比如,现在有5个数{5,1,2,7,8}
输入之后开始调用函数环节,
第一次传入的left为1,right为5
函数确定了它第一次的基准数为5,
开始寻找了,
j=5,a[5]=8,大于基准数,所以j–,
a[4]=7,大于基准数,j–,
a[3]=2,小于基准数,对于j的循环处理退出,
开始i的处理,
i=1,a[1]=5,就是基准数,所以跳过,i++,
a[2]=1,小于基准数i++,
i=3,此时i==j了,退出对i的循环处理,
判断一下i和j的大小,如果i<j,那么就交换两个数的位置,因为还没到两个循环点碰头的位置,如果i= =j,说明那么此时i和j就碰头了,这一次的基准数左右交换也就停止了
将基准数与i,j碰头的地方交换
此时的数列变成了{2,1,5,7,8}
然后开始进入函数中的函数(磨人递归)
传参为left=1,right=i-1=2;
left<right,开始循环判断,
选择a[1]为基准数,
j=2,a[2]=1,小于基准数,退出j判断循环,
i=1,a[1]=2,为基准数,i++
i=2,i= =j,退出i判断循环
因为i= =j,所以不交换,进入基准数与碰头数的交换环节
此时数组为{1,2,5,7,8}
虽然排序已经成功,但程序还没完成
具体递归且二分环节。。。我们暂且略过,递归磨人,不要深究
emmm但大概还是要理解一下的,因为每次进入函数时,都是传入左边值和右边值,然后找出基准数,对左右边界值内部的数与基准数不断比较与交换,然后再进入函数中的函数,再将刚刚的部分继续拆分,直到left>=right再返回上一层函数,然后进入后半段的比较交换,然后成功后函数再拆分再比较,再交换,直至所有的数被排序好,再一层一层退出循环,然后得到已经排好序的数列


最后的最后要附上我的错误代码,关于我的易错点

#include<stdio.h> 
int n,a[100000];
int quicksort(int left,int right)//错处
{ 
 	int temp,i,j,flag;
 	if(left>right)
  		return;
 	temp=a[left];
 	i=left;
 	j=right;
 	while(i!=j)
 	{
  		while(a[j]>=temp&&i<j)
   			j--;
  		while(a[i]<=temp&&i<j)
   			i++;
  		if(i<j)
  		{
   			flag=a[i];
   			a[i]=a[j];
   			a[j]=flag;
  		}
	}
 	a[left]=a[i];
 	a[i]=temp;
 	quicksort(left,i-1); 
 	quicksort(i+1,right);
}
int main()
{
 	int i;
 	scanf("%d",&n);
 	for(i=1;i<=n;i++)
  		scanf("%d",&a[i]);
 	quicksort(1,n);
 	for(i=1;i<=n;i++)
  		printf("%d ",a[i]);
 	return 0;
}

关于这个错处,因为这个函数是没有返回值的,函数排序的过程已经对数组进行了更改,所以函数类型用void,不要顺手int


再来增加一点,就是搜索i,j的位置交换时,一定要从j(基准数的对立面)查起,不要先查i,因为从i查起,i 停留的位置一定比基准数大,然后判断j,j与i相遇时(记此点为交换点),交换点的数一定大于基准数,这样比基准数大的数最后就会被交换到基准数的左边

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值