算法 快速排序
@author:Jingdai
@date:2020.10.28
今天刷 LeetCode,发现以前学的快排又忘记了,现记录一下,希望以后不会再忘了。
简介
快排,即快速排序。嗯,没啥说的,直接看思路吧。
思路
思路一句话概括就是确定数组中一个数
pivot
,然后将小于它的数全部放在它左边,把大于它的数全部放在它右边。然后递归对它左边的子数组和右边的子数组调用同样的算法即可完成排序,看下面的代码片段。public static void quickSort(int[] array, int left, int right) { if (left >= right) { return; } int pivot = positionAndGetPivot(array, left, right); quickSort(array, left, pivot - 1); quickSort(array, pivot + 1, right); }
看上面的代码就会发现,其实主要的问题就是选取一个
pivot
,并将小于它的数放其左边,大于其的数放其右边。那选择哪个数作为pivot
呢?为简单起见,这里先选择数组最左边的数作为pivot
,然后用两个指针变量left
和right
记录数组的最左边下标和最右边下标。如图,先从右边找一个比pivot
上数小的数,将它移到左边,然后从左边找一个比pivot
上数大的数,将它移到右边,一直循环直到left
等于right
。然后将pivot
的值放入left
的位置上即可(此时left
和right
相等)。其实整个过程有点像交换两个变量值的算法,需要利用一个中间变量,只是这里用一个变量记录pivot
上的值,然后从右找一个数放它的位置上,右边那个位置又可以放其他数了,然后从左边找一个数放右边,一直到left
和right
相等,然后将原来中间变量即记录的pivot
的值放在这个位置上。看下面的代码片段。
public static int positionAndGetPivot(int[] array, int left, int right) { int pivotValue = array[left]; while (left < right) { while (left < right && array[right] >= pivotValue) { right --; } array[left] = array[right]; while (left < right && array[left] <= pivotValue) { left ++; } array[right] = array[left]; } array[left] = pivotValue; return left; }
但是上面代码还有一点点问题,当数组中的数的随机性不好时,快排的效率不是很理想,这里我们可以手动引入随机性。上面每次选择数组中最左边的数作为
pivot
,我们可以随机选择pivot
,这样就可以防止因为数组随机性不足导致的效率问题。做法很简单,在left
和right
中随机选择一个下标作为pivot
,然后将选择的数与array[left]
交换就好了,看下面的代码片段。public static int positionAndGetPivot(int[] array, int left, int right) { Random r = new Random(); int pivotIndex = r.nextInt(right - left + 1) + left; int pivotValue = array[pivotIndex]; array[pivotIndex] = array[left]; while (left < right) { while (left < right && array[right] >= pivotValue) { right --; } array[left] = array[right]; while (left < right && array[left] <= pivotValue) { left ++; } array[right] = array[left]; } array[left] = pivotValue; return left; }
完成
pivot
位置选取的函数后,然后递归调用这个算法就可以完成快排了。完整代码如下。
代码
public static void main(String[] args){ int[] array = { 4, 5, 9, 2, 1, 4, 1, 3, 5, 6, 7}; quickSort(array); System.out.println(Arrays.toString(array)); } public static void quickSort(int[] array) { quickSort(array, 0, array.length-1); } public static void quickSort(int[] array, int left, int right) { if (left >= right) { return; } int pivot = positionAndGetPivot(array, left, right); quickSort(array, left, pivot - 1); quickSort(array, pivot + 1, right); } public static int positionAndGetPivot(int[] array, int left, int right) { Random r = new Random(); int pivotIndex = r.nextInt(right - left + 1) + left; int pivotValue = array[pivotIndex]; array[pivotIndex] = array[left]; while (left < right) { while (left < right && array[right] >= pivotValue) { right --; } array[left] = array[right]; while (left < right && array[left] <= pivotValue) { left ++; } array[right] = array[left]; } array[left] = pivotValue; return left; }