18、排序算法-快速排序
来源:https://www.bilibili.com/video/BV1B4411H76f?p=60
一、思路
快速排序:是交换排序中的一种,属于冒泡排序的改进方法。在数据中间找到一个基准值,如果想从小到大排列,比基准值小的放在基准值的左边,比基准值大的放在基准值的右边。然后左边右边分别递归快速排序。
例如:[-9,78,0,23,-576,70],从小到大排列
方法开始设置左边的起始位置下标l = 0,右边的起始位置下标r = arr.length-1,以及基准值,基准值可以在数组中随意选择,这里选择的是pivot=arr[(l+r)/2],即数组中间位置的数据作为基准值。
第一趟:从l和r分别开始找比基准值小(右边)和大(左边)的数据。
这里基准值是0。-9小于0,l++,在左边找到了比0大的数78,此时l=1;
继续在右边找,70大于0,r--,在右边找到了比0小的数-576,此时r=4。
交换两个数[-9,-576,0,23,78,70]。此时l=1所在的位置已经小于基准值,l++,到0了,l=2;
继续右边,r=4所在的位置已经大于基准值,r--,r=3的位置数据依然大于基准值,r--,此时r=2=l。本次左右两边的数据比较完毕,结束。
左边[-9,780],0,[23,78,70]右边。
第二趟,以同样的形式递归左边和右边。以下都是这样。
这样说不清楚,一会单步调试看一下。
二、实现
1 //快速排序 2 public class QuickSort { 3 public static void main(String[] args) { 4 int[] arr = {-8,-9,78,0,23,-567,70,-7}; 5 System.out.println(Arrays.toString(arr)); 6 int left = 0; 7 int right = arr.length - 1; 8 9 quickSort(arr,left,right); 10 System.out.println(Arrays.toString(arr)); 11 } 12 13 public static void quickSort(int[] arr,int left,int right){ 14 int l = left;//左边的起始位置 15 int r = right;//右边的起始位置 16 int pivot = arr[(left+right)/2];//中间值(基准值) 17 while(l < r){ 18 //遍历左边找比基准值大的 19 while (arr[l] < pivot){ 20 l += 1; 21 } 22 //遍历右边找比基准值小的 23 while (arr[r] > pivot){ 24 r -= 1; 25 } 26 if(l >= r){ 27 //此次比较已经完全遍历了整个数组 28 break; 29 } 30 //找到了对应的数据,交换 31 int temp = arr[l]; 32 arr[l] = arr[r]; 33 arr[r] = temp; 34 35 //还有一种可能,遍历到了基准值,同样满足跳出上面两个while的条件,基准值也要交换 36 //交换完成后,基准值的位置发生了改变 37 if(arr[l] == pivot){ 38 //这个基准值是从右边换过来的 39 r -= 1; 40 } 41 if(arr[r] == pivot){ 42 //这个基准值是从左边换过来的 43 l += 1; 44 } 45 } 46 47 //接下来开始迭代了,但是要避免一个情况,l和r最终在一个位置,那么递归会重复中间的数据 48 if(l == r){ 49 l += 1; 50 r -= 1; 51 } 52 if(left < r){ 53 quickSort(arr,left,r); 54 } 55 if(right > l){ 56 quickSort(arr,l,right); 57 } 58 } 59 }
结果
[-8, -9, 78, 0, 23, -567, 70, -7]
[-567, -9, -8, -7, 0, 23, 70, 78]
单步调试:
第一次进入方法
找到左边的坐标(2)和右边的坐标(7),交换数据后[-8, -9, -7, 0, 23, -567, 70, 78]
下一波,左边(3),右边(5),左边到基准值的位置了,依然交换[-8, -9, -7, -567, 23,0, 70, 78]
这时候下边的判断就有用了,基准值交换到了右边,所以左边的继续++(4),继续和基准值比较,交换
下一波,左(4),右(5),还是交换[-8, -9, -7, -567,0,23, 70, 78],但是基准值换到了左边,所以右边--(4)再与基准值比。但是r=4也满足下面的判断,所以l++(5)
好了,现在满足退出while的条件了,整个数组遍历完成了,继续下去就是迭代的过程了。