欢迎各位小可爱~ 我们一起学习,共同进步吧~
一、 快排的原理:一般分为三步: 1.从待排序区间选择一个数,作为基准值(一般选最左边的数) 2.Partition:遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的放到(可以包含相等的)放到基准值的右边。 3.采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度<=1,则退出比较。 以数组[3,5,2,7,9,4,8]为例,进行快排的过程: 二、比较的过程就是Partition的过程, java实现快速排序Partition部分有三种方法: 1 Hoare法 2.挖坑法 3.前后遍历法 Hoare法的思想:
挖坑法的思想:基本思路和Hoare法一致,只是不再进行交换,而是直接赋值(挖坑+填坑)
前后遍历的思想:从第二个数开始遍历,找出比第一个数字小(或大)的数字,然后和第一个数字交换,思想也比较简单,大家看代码就能看懂。
三、 性能分析: 时间复杂度:最好O(nlog(n)) 最坏O(n^2) 平均复杂度:O(nlog(n)) 空间复杂度:最好:O(nlog(n)) 最坏:O(n) 平均:O(nlog(n)) 稳定性:不稳定
四、 关于快排的优化方法: 一般面试官问的时候就从这几个方面考虑就行了。 1.paitition部分里的挖坑(小细节优化) 2.当比较的数字比较少的时候,快排不是最快的;(当区间内的个数低于某个阈值(16)时,使用插排) 3.优化选择特殊的数的方式-----现在选最左边的数字为比较值 a.随机选 b.选几个数,挑大小值为中间的(三数取中) 4.把相等的值特殊处理
五、快速排序的代码实现部分:(三种方法)都是实现从小到大的排序
public class Hoare { public static void quickSort(long[] array) { quickSortInternal(array, 0, array.length - 1); } // 区间是 [lowIndex, highIndex] private static void quickSortInternal(long[] array,int lowIndex,int highIndex) { // 由于是闭区间,所以,区间内个个数需要加个 1 int size = highIndex - lowIndex + 1; if (size <= 1) { return; } // 选择其中一个数(选最左边的) —— array[lowIndex] // 执行 partition,小的放左,大的放右 // keyIndex 是经过 partition 之后,选出来的数最终所在下标 int keyIndex = partition(array, lowIndex, highIndex); // 分别对左右区间进行相同的处理 —— 递归方法 quickSortInternal(array, lowIndex, keyIndex - 1); quickSortInternal(array, keyIndex + 1, highIndex); } // 区间是 array[lowIndex, highIndex] // 1. 选择 array[lowIndex] 作为特殊的数 // 2. 需要遍历整个区间(不能遗漏任何的数)和 选出来的数比较 // 3. 保证 小于等于的在左边,大于等于的在右边(但没有顺序要求) private static int partition(long[] array, int lowIndex, int highIndex) { // 选择合适的方法 return partitionHover(array, lowIndex, highIndex); } private static void swap(long[] array, int index1, int index2) { long t = array[index1]; array[index1] = array[index2]; array[index2] = t; } private static int partitionHover(long[] array, int lowIndex, int highIndex) { int leftIndex = lowIndex; int rightIndex = highIndex; // 选择的数是最左边的一个 long key = array[lowIndex]; // 选择了最左边,从右边先走 // 停止条件 leftIndex == rightIndex // 循环的继续的条件 leftIndex < rightIndex while (leftIndex < rightIndex) { while (leftIndex < rightIndex && array[rightIndex] >= key) { rightIndex--; } // 说明 [rightIndex] 遇到了小的了 while (leftIndex < rightIndex && array[leftIndex] <= key) { leftIndex++; } // 说明 [leftIndex] 遇到了大的了 swap(array, leftIndex, rightIndex); } swap(array, lowIndex, leftIndex); return leftIndex; } //挖坑 private static int partitionHoare(long[] array,int lowIndex,int highIndex){ int leftIndex=lowIndex; int rightIndex=highIndex; long key=array[lowIndex]; while(leftIndex<rightIndex){ while(leftIndex<rightIndex&&array[highIndex]>=key){ rightIndex--; } //右边的值 array[leftIndex]=array[rightIndex]; while(leftIndex<rightIndex&&array[leftIndex]<key){ leftIndex++; } array[rightIndex]=array[leftIndex]; } array[leftIndex]=key; return leftIndex; } //前后遍历的方法 private static int partition前后(long[] array,int lowIndex,int highIndex){ int separateIndex=lowIndex+1; for(int i=lowIndex+1;i<=highIndex;i++){ if(array[i]<array[lowIndex]){ swap(array,i,separateIndex); separateIndex++; } } swap(array,lowIndex,separateIndex-1); return separateIndex-1; }