快速排序解析(简介,源码,原理,为什么从右端开始扫描?)

简介:

快速排序是一种效率较高的排序算法,采取了分治和二分的思想对冒泡排序进行改进,快速排序的原理很简单,但是仍然有需要注意的地方。

原理:

举个例子,给我们 5 3 10 4 1 2 6 8 7 9这样十个无序的数,让我们从小到大排序,如果采用冒泡排序的方法,那就是用相邻两个数交换的思想,遍历9次,就完成了排序,虽然原理很简单,但是牺牲了时间效率,我们不妨大胆一些,如果我们一趟不是只找出一个数呢?这就引出了快速排序:
首先,我们找出一个基准数,这里为了方便,我们选取第一个数,也就是5作为基准数进行排序最后要达成一个目标,5的左面都是小于5的数,5的右边都是大于5的数,我们该怎么做呢?(请思考五分钟,写写画画)
方法如下:
在这里插入图片描述
我们用红色箭头指向第一个数,用蓝色箭头指向最后一个数,先让蓝色箭头先动,这点很重要,为什么会在文中解释,让蓝色箭头一直往前遍历,直到找到第一个比5小的数(因为右边最后都是大于5的数,也可以说现在正在排除异己),找到之后停下,然后红色箭头开始动,往后动,直到找到第一个比五大的数停下,完成时如下:
在这里插入图片描述
找到了两个不属于自己阵营的数,让他们归位,也就是进行交换。
在这里插入图片描述
现在,重复遍历的步骤,蓝色箭头先动:
在这里插入图片描述
然后再让红色箭头往后找,但这时我们发现,在找的过程中,红色箭头与蓝色箭头相遇了,这时,我们就可以停止再往下遍历了,再过去就都是蓝色箭头的阵营了,就不礼貌了(这也是非常重要的一点,在目前从小到大排序的前提下,时刻保证红色箭头在蓝色箭头的左边在这里插入图片描述
现在我们再让基准数与箭头停止的地方进行交换
在这里插入图片描述
这时,就已经达成了我们目标,左小右大,可是现在还是没有完成排序啊,我们采用分治的思想,对基准数的左面和基准数的右面重复进行排序,
例如:左面的数现在是 1 3 2 4,以1为基准数
在这里插入图片描述
我们发现,第一轮遍历箭头就已经在1处聚集了,那就说明1已经是最小的数了,由于1只有右区间,没有左区间,我们现在对右区间进行排序。
在这里插入图片描述
基准数为3,经过排序后我们发现,这回排序以后,就是有顺序的数了
在这里插入图片描述
现在最开始基准数5的左面就是 1 2 3 4,我们实现了从小到大的排序,那么对5的右区间也是一样,经过重复,顺序形成。
左右区间的重复排序可以用递归的方法完成,这就是快速排序。

注意点(为什么从右面开始扫描):

回过头来,我们再说以下,为什么要从右侧先开始遍历呢,主要两点,现在我们回到最开始那个例子来说明一下:

在这里插入图片描述

这回,我们先从红色箭头开始动,由于下面的步骤和上面一样,我们就直接跳过到有价值的地方:
在这里插入图片描述

经过一次交换以后,如图上所示,现在我们开始从红色箭头开始,往后寻找
大于5的数,
在这里插入图片描述
现在我们发现,在10处,箭头相遇了,我们之前说箭头相遇就是扫描停止的标志,那我们现在停止扫描,并把基准数和箭头所指处进行交换:
在这里插入图片描述
我们发现了一个尴尬的事,10到了小的那一侧,这也是第一个错误,先让右面动,其中一个原因就是右面往前找的是小于5的数,那么在交换基准数之前,箭头交汇的位置就是小于5的数,这样符合我们左小右大的排序原则,如果是从左开始往右遍历,我们得到的就是大于5的数了,因为左面往右找的是大于5的数。
第二个原因是什么呢?我们举个例子来说明一下:
假如需要我们排序的数列是:6 1 2 3 4 5 3 4 7 8在这里插入图片描述

基准数为6,只不过我们这回先从左往右开始扫描:
在这里插入图片描述

这时,你再让蓝色箭头往前动,我们发现箭头居然在7处就交汇了,蓝色箭头没有找到一个小于5的数就被迫停止了,这明显不符合我们算法左小和右大交换的原则,并且在7处交汇以后,由于7本身是比6大的数 交换基准数之后反而把大的七交换到了左边,这就出现了错误,所以从左边取基准数,要从右端开始扫描,反之 从右边取基准数,要从左边开始扫描,这是因为 如果从右边开始扫描,找到的第一个数可能本来就在左区间 ,并且小于基准数 这样你左侧指针启动交汇以后,把小的数换给了最右边的基准数,也就出现错误了

源代码:

int a[101], n;
void quicksort(int left, int right)
{
	int i, j, t, temp;
	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)
		{
			t = a[i];
			a[i] = a[j];
			a[j] = t;
		}
	}
	a[left] = a[i];//基准数归位
	a[i] = temp;

	quicksort(left, i - 1);
	quicksort(i + 1, right);
}

快排的基本介绍就到此为止了,注意那一部分感觉还是有瑕疵,恳请诸位指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值