快速排序算法分析

快排的难点不是在思想,而是在于有多种情况,然后要求你写出来的代码可以满足所有的情况,你不确定自己的代码写出来是不是健壮的,于是需要我们主动去分析各种情况,然后提炼出多种情况中真正共通的特性,这样才能使写出来的代码比较精炼和精准,而不是说需要你分多钟情况去讨论。
从网上可以看到很多代码都是短小精炼,精炼到你看不懂,所以还需要自己去主动总结多钟情况的共同特点。
经过下面自己的梳理,会发现,快速排序最重要的两点顾虑:

  1. 在当前循环过程中,防止进入死循环
  2. 在当前循环结束后,准备递归时,要防止进入死递归

共同点:
先定好pivot为数组第一个元素。
其次,要知道,不管对于哪种情况,每一轮循环结束的条件都是两个用于遍历的指针相遇了,于是该轮循环结束了,开始递归。这是一个很重要的共同点。
再有一个共同点,因为pivot选的是数组的第一个元素,所以,每一轮循环的开始,第一个元素总会面临可能互换的情况,唯一不会被互换的情况,就是pivot就是元素中唯一的最小值。
另一个共同点,就是对左右递归条件的判断,不管是属于哪种情况下结束的当前循环,进入递归的判断都是一样的,需要考虑还需不需要进行左递归或者右递归,这也是整个递归过程的终止条件,比如说,如果左边部分的元素个数为0或者1,那不用进行左递归了,对右边也是同理。要考虑防止进入死递归

简单一点的情况就是整个数组元素各不相同,这样,在循环的过程中不会有两个相等的元素面临交换位置的情况。
即使对于这个简单一点的情况,也可以再细分:
第一种情况,pivot右边的数字都比pivot大,即pivot是数组中的最小值
对这种情况,循环的两个指针最终都会指向下标0,两个指针相等的情况,就是循环终结的条件,所以不会产生互换。接着开始右递归。
第二种情况,pivot右边的数字都比pivot小,即pivot是数组中的最大值
这种情况,数组一开始就会互换,然后循环的两个指针最终相遇到数组最后的下标上,两个指针相等,该轮循环结束。接着开始左递归。
第三种情况,不是上面两种极端情况,pivot并非数组的最值
可以想象,这种情况就是最理想的情况,很多关于该算法的讲解都是举这样的情形作为示例的,显然这种情况是最简单的,一定会产生pivot最后落在数组中间的某个下标上,而不是首尾,然后两个指针相遇在这个下标上,接下来,开始左、右递归。
对于以上三个情况,都不需要动用到循环内部的保护判断代码

两个相等的元素面临互换的情况(即数组中有两个甚至多个相等的元素),这里得说明一下,两个相等的元素面临互换的情况是有限的,这两个元素得都等于pivot
继续细分:
第一种情况,pivot为数组最小值
第二种情况,pivot为数组最大值
对于以上两种情况,可以分析得出他们的互换就是循环过程中的第一次互换。需要对这样的情况进行判断,防止进入死循环
第三种情况pivot不是最值
对于这种情况,这些相同的值一定会在当前循环快要结束的时候面临互换,且一定会进行互换,于是也要做好防护,防止进入死循环。
对于上面三种情况,可以总结出这种情况中最大的共同点就是,不管两个等于pivot的值是在什么时候相遇的,不管pivot是否为最值,都要防止进入死循环,且只要能防止进入死循环,就可以到达最终当前循环的结束条件,首尾指针相遇

public static void quickSort(int[] arr, int start, int end) {
		int pivot = arr[start];
		int left = start;
		int right = end;
		int temp = 0;

		while (left < right) {
			// 下面两个循环是找可以互换的元素的
			while (arr[left] < pivot) {// 为了从左边去找到大于等于pivot的数
				left++;
			}
			while (arr[right] > pivot) {// 为了从右边去找到小于等于pivot的数
				right--;
			}

			// 意味着当前循环圆满结束,可以进行下一轮递归了
			if (left == right) {
				break;
			} else {// 互换一次,先互换再判断
				temp = arr[left];
				arr[left] = arr[right];
				arr[right] = temp;
			}

			// 对有元素相等的情况进行防护,防止当前循环进入死循环
			if (arr[left] == arr[right]) {
				// 这里不需要再说&&left < right了,因为如果相等的话,上面直接break了
				left++;// 或者right--也行,让指针继续动
			}
		}

		if (left - 1 > start) {// 说明左边至少有两个元素,可以左递归
			quickSort(arr, start, left - 1);
		}
		if (right + 1 < end) {// 说明右边至少有两个元素,可以右递归
			quickSort(arr, right + 1, end);
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值