快速排序
- 简介
快速排序(Quicksort)是对冒泡排序的一种改进。 快速排序由C. A. R. Hoare 在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
- 基本思想
1)选择一个基准元素,通常选择第一个元素或者最后一个元素,
2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大。
3)此时基准元素在其排好序后的正确位置
4)然后分别对这两部分记录用同样的方法继续进行排序(递归),直到整个序列有序。 - 图解
首先设置一个基准点paivot,一个left指针和一个right指针,如图所示:
left指针用于寻找比基准值大的数,right指针用于寻找比基准值小的数
step1. 从右指针right开始向左移动(这个很重要,必须从右指针开始移动,下面再给出解释),当找到一个比基准值小的时候停止移动。
step2. 左指针left开始移动,当找到一个比基准值大的时候停止移动。
step3. 交换左右指针所指的值。
step4. 重复1、2、3步,直至left不等于rightleft != right
时,停止,然后交换基准值和两个指针所同时指向的值。此时基准值右边全是大于它的数,左边全是小于它的数。
step5. 再分别对基准值左半部分和右半部分进行上述步骤,直至推出循环。
下面的步骤大同小,大家可以可以自己去画一下,还能帮助理解。
- 代码实现
public static void quickSort(int[] arr,int left,int right){
if (left > right){//递归的退出条件
return ;
}
int temp = 0;
int paivot = left; //基准点
int base = arr[paivot]; //base用于保存基准值,便于下面的交换
int i = left, j = right;
while(i != j){
//右指针移动
while(arr[j] >= base&& i < j){
j--;
}
//做指针移动
while(arr[i] <= base&& i < j){
i++;
}
if (i < j){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//交换基准点的值
arr[left] = arr[i];
arr[i] = base;
//递归
quickSort(arr,left,i-1);
quickSort(arr,i+1,right);
}
- 注意
还记得我们在上面留下了一个问题,大家可以想一下为什么不能先移动左指针,而一定要先动右指针。接下来给大家解释一下,我在网上也看到了好多的解释,但是还是觉得不是很直观,有点模棱两可,所以我先解释然后用图解的方式演示一遍。
原因:先移动右边的指针是为了保证每次推出循环,和基准点的值做交换的那一个数据,一定是小于基准值的,而要是先移动左指针效果就不一定是那样了,语言不好理解,我们直接用图解来看一下。
先移动左指针:如图左指针停下来了
再移动右指针:此时右指针没动,因为2小于3
交换,然后在去移动,然后再交换:
注意马上就要出错了: 重复上述步骤,此时指针位置如图:
看上图,可知两个指针已经相等了,应该退出循环,交换基准值了,但是大家发现没有此时指针所指的数据为 6,如果交换之后它位于3的左边如下图,是不符合快速排序的规则的(基准值左边的数比它小,右边比它大)
这也就是为什么一定要先移动右指针的原因,大家一定要注意,此处不能去创新。 - 总结
学习排序算法是一个很有趣的过程,大家在学习过程当中一定要多想,不能光看,多动手,多敲键盘,画图也是对于学习算法的一个重要手段,谢谢你们的阅读,希望大家相互学习,共同成长。