本文大部分知识点来源于知乎专栏:Java必学知识
快速排序(QuickSort)是对冒泡排序的一种改进。快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:
从要排序的数据中取一个数为“基准数”。
通过一趟排序将要排序的数据分割成独立的两部分,其中左边的数据都比“基准数”小,右边的数据都比“基准数”大。
然后再按步骤2对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
该思想可以概括为:挖坑填数 + 分治法。
分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。在计算机科学中,分治法就是运用分治思想的一种很重要的算法。分治法是很多高效算法的基础,如快速排序,归并排序,傅立叶变换(快速傅立叶变换)等等。
/**
* @param arr 需要排序的数组
* @param low 开始时最左边的索引=0
* @param high 开始时最右边的索引=arr.length-1
*/
public static void quickSort(int[] arr,int low, int high){
if(low >= high){
return;
}
//取最左边的数作为基准位
int i = low,j = high,index = arr[i];
while (i < j){
//从右向左寻找第一个小于index的数,当arr[j]<index时,下面这个while循环会结束
while (i < j && arr[j] >= index){
j--;
}
//将找到的arr[j] 填入arr[i],同时将i右移
if(i<j){
arr[i++] = arr[j];
}
//从左向右寻找第一个大于index的数
while (i < j && arr[i] < index){
i++;
}
//将找到的arr[i] 填入arr[j],同时将j左移
if(i < j){
arr[j--] = arr[i];
}
}
//将基准数填入最后的坑
arr[i] = index;
//对基准数两边的数组再进行上面的操作
quickSort(arr, low, i - 1); // 递归调用,分治
quickSort(arr, i + 1, high); // 递归调用,分治
}
最好情况的时间复杂度为O(nlogn),过程比较复杂,就不在此赘述。
最差情况下每一次取到的数(基准数)都是当前要比较的数中的最大/最小值,
在这种情况下,每次都只能得到比上一次少1个数的子序列(即要么全比基准数大,要么全比基准小),
此时相当于一个冒泡排序,比较的次数 = (n - 1) + (n - 2) + … + 2 + 1 = (n - 1) * n / 2,此时的时间复杂度为:O(n^2)。
最差情况一般出现在:待排序的数据本身已经是正序或反序排好了。
基本上在任何需要排序的场景都可以使用快速排序。虽然快速排序的最坏情况时间复杂度为O(n^2),但是由于基本不会出现,因此可以放心的使用快速排序。在本人的电脑测试,100万的随机数字,快速排序大约耗时120毫秒。
Written on June 3rd , 2020 by joonwhee