快速排序的疑难杂症

最近要准备蓝桥杯和学校的程序设计的比赛,所以拿起了多少年没看过的算法了,一看发现自己的知识网全是漏洞了(毕竟两年了),所以开始重新复习和学习,希望自己能重新拾起自己原来的本领并甚至更进一步。

重新摸起算法,就不得不说不说起算法的入门虎之一的快速排序,当年也是被折磨的死去活来的,但是如今看看网络上的教程,突然发现其实快排很简单(大概)

首先放图,解释快排的思想(摘自啊哈算法):

确实,快速排序的根本思想其实和冒泡排序差不多,就是找到一个数排序后应该在的位置,然后把他放进去,而在快速排序中体现的方式就是,找到一个基准数,然后把比他大的放在左边,比他小的放在右边(此时他的位置不就是他应该在的位置嘛!!),所以其实每一轮快速排序都是为一个数的排序。然后对他左面和右边未排序的数字进行排(分治思想)。

其次,对于该先移动哪个哨兵的解释:

假如你要将比你大的数放在右面,则你需要,首先移动左哨兵,因为在左右哨兵相遇的最后一次移动中:

1.假如最后是右哨兵碰上左哨兵,则此时两者指向的值一定是比基准值小的(因为左哨兵没有动,而在上一轮左哨兵指向的点是交换为一个比基准值小的值)。

2.假如是左哨兵碰上右哨兵,此时指向的仍是一个比基准值小的值,因为,左哨兵已经探索完并停下,说明他指向的是一个比基准值小的点,否则他不会停下。

综上,因为基准值选的为第一个点,也就是说无论如何交换,和基准值交换的一定要为一个一个比他小的值,否则在最后一轮排序后,会导致比基准值大的值出现在基准点的左面,发生错误,如果你是打算降序排序,仍需要先让左哨兵移动(基准值为第一个)。

 

当然,也有不需要考虑移动哪个哨兵的方式:

 我们可以不需要去移动基准点,只是随便找个基准值,让大于他的,都在最后i,j相遇的地方(记为k),让k前的数大于等于基准值,而k后面的值均小于基准值(降序还是升序由你自己决定,此处只是举个例子),然后对k之前的和后面的分别重复如上过程,最后在分治算法的思想指导下,每个序列都各自为有序数列,且各个序列之间也为有序数列,即将整个问题分成无数个小问题去解决,而此时,先移动哨兵还是后移动哨兵并没有区别,你不需要找到一个位置去放基准点(就是找到基准点在按升序应该在的位置),这种思想并不是去给一个点找到他应该在的位置,而是以他的值将序列分为两个部分,在有限次划分后,当剩下只有一个数字的序列时,整个序列就是有序的了!

下附代码:

void pai(int h,int e)
{
	int mid=a[(h+e)/2],k=h,j=e,temp;
	do
	{
		while(a[k]<mid)k++;//这句和下面的语句可以换位置
		while(a[j]>mid)j--;
		if(k<=j)
		{temp=a[k];a[k]=a[j];a[j]=temp;k++;j--;}
	}
	while(k<=j);
	if(k<e)pai(k,e);
	if(j>h)pai(h,j);
}

对于以上两种方式实现的快排我还没有进行速度比较,待更新。

最后:

希望你能找到属于自己的快排实现算法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值