快速排序中容易出错的点

我自己在学习快排的时候看了不少大佬们的博客,反复对比一直觉得自己写的没问题,直到最后才发现这一点点细微的差别能导致这么大的问题,所以想给初学者们一起分享一下。

下面是一段正确的快排代码

void QuickSort(int first,int last)
{
	if (first >= last)
		return;
	int left = first, right = last, base = arr[left];
	while (left < right)
	{
		while (arr[right] >= base && left < right)
			right--;

		while (arr[left] <= base && left < right)
			left++;
		swap(&arr[left], &arr[right]);
	}
	swap(&arr[first], &arr[left]);
	QuickSort(first, left - 1);
	QuickSort(left + 1, last);
}

这里以第一个元素做为基准base,并且right的移动先于left

而假如我们进行一点小小的改动,它就寄了,这些是刚接触这个算法的时候很容易犯的错误

一,left和right的移动顺序很重要

        对调left和right移动的顺序(或者令最后一个元素为基准base)

        while (arr[left] <= base && left < right)
			left++;
        while (arr[right] >= base && left < right)
			right--;
		swap(&arr[left], &arr[right]);

        为什么?在所有元素还没有排成顺序的情况下,如果left停止移动了,则说明left左侧的元素全部小于等于基准,并且left对应的元不大于基准(废话)

        此时如果right移动到left的位置,则会自动停止,此时不会发生交换(自己跟自己换),而left对应元素是大于基准的,当循环结束后跟首元素(基准)互换,左边就出现问题了。

        而如果让right优先移动,则left == right时这个元素是小于基准的(不满足right的条件),因此换到左边是不会出现问题的。当然,把最后一个元素作为基准就需要先移动left了

二,与基准的比较需有'='

        可能会有人跟我一样,想着少个'='不就是多换一次而已吗,有什么大不了。

        但这就大错特错力(。一旦遇到另外两个基准数,程序就不动了。比如取4 1 2 4 5 4。left碰到一个基准,不动了,right也是不动了,二两者进行交换没有任何意义。于是,寄。

三,在left == right时,基准的交换不能贪小便宜

        就是把swap(&arr[first], &arr[left]); 写成swap(&arr[first], &arr[left - 1]);  其实贪不了,但是我一开始以为能贪一手(我是笨比)

        如果你已经弄明白了left和right移动的顺序,那可能会觉得这个错误不可思议,因为left == right的点应当移到基准左边来。而如果你也没搞清楚顺序,那这种做法可能会使某些数据输出正确的结果,但这是一种假象,会让人看半天不知道自己错在哪

        比如对于:3 1 2 4 5,前一种写法会输出1 2 4 3 5。而后一种(left - 1),成功避免了把大于基准的这个数换到左边,就能输出正确的结果(但还是错的)。让我们来分析一下:left先移动问题无非出现在两者相等的点

         第一轮移动left和right便发生了重合,随后3和4换位,然后分成了以下两个区间。基准3不会被分入区间,5单独一个也没有排序的必要

                           

        对于前面这个,left和right在数字2处相遇,4和2交换变成2 1 4

        最后对于2 1,再进行互换,然后结束

        然后如果是用的后一种(left - 1),第一次3和2交换,得到2 1 3,随后2 和1交换,最后一次只有两个元素,所以自己和自己交换,故得出正确结果。

        那如果用后一种也能成功排序吗?肯定不是。当遇到凸型数据(左右小,中间大)时,如       3 4 5 4 3,就会发生错误(输出了3 4 4 5 3)。

        让我们以3 4 5 4 3为例来看一下:

        第一次(分割前)的第一次移动:left移动到第二个位置(数字4),right一直满足条件,也来到这里,然后3和自己互换。

        第二次:分割出了(需要处理的)5 4 3,left一直满足条件,来到3,随后4和5互换,然后就出现这个结果了

        这个写法的错误跟第一种反了过来,第一种是由于把不该换的数据换到了左边,而这种是没能把右侧该换的数据换过来

 

 

        

        

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值