快速排序(Quicksort),又称划分交换排序,简称快排,一种排序算法,最先由东尼·霍尔提出。在平均情况下,排序n个项目要O(n log n)次比较。在最坏情况下则须要O(n^2)次比较,但这种情况并不常见。java
事实上,快速排序O(n log n)一般明显比其余算法更快,由于它的内部循环能够在大部分的架构上颇有效率地达成。算法
快速排序使用分治法策略来把一个序列分为较小和较大的2个子序列,而后递归地排序两个子序列。数组
步骤为:架构
挑选基准值:从数列中挑出一个元素,称为“基准”(pivot),函数
分割:从新排序数列,全部比基准值小的元素摆放在基准前面,全部比基准值大的元素摆在基准后面(与基准值相等的数能够到任何一边)。在这个分割结束以后,对基准值的排序就已经完成,性能
递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。ui
递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。指针
选取基准值有数种具体方法,此选取方法对排序的时间性能有决定性影响。code
快速排序的算法步骤我给划分为5步:排序
public class QuickSort { public static void qSort(int[] arr, int head, int tail) { if (head >= tail || arr == null || arr.length <= 1) { return; } //定义俩指针 用于移动 int left = head; int right = tail; int pivot = arr[head]; //基准值,也能够arr[(head + tail) / 2] while (left <= right) { while (arr[left] < pivot) { //左指针先走,找到大于等于基准数的中止 ++left; } while (arr[right] > pivot) { //右指针后走,找到小于等于基准数的中止 --right; } if (left < right) { //交换arr[left]和arr[right]的位置 int t = arr[left]; arr[left] = arr[right]; arr[right] = t; //继续遍历 ++left; --right; } else if (left == right) { //遍历完,错开两指针 ++left; //break; } } qSort(arr, head, right); qSort(arr, left, tail); } public static void main(String[] args) { int[] arr = new int[]{6, 1, 2, 7, 9, 3, 4, 5, 10, 8}; qSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } }
打印输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
在程序运行中,能够经过打印排序前和排序后的数列观察运行流程
对数组 [6 1 2 7 9 3 4 5 10 8 ] 排序, 排序后 [5 1 2 4 3 9 7 (6) 10 8 ] 对数组 [5 1 2 4 3 ] 排序, 排序后 [3 1 2 4 (5) 9 7 6 10 8 ] 对数组 [3 1 2 4 ] 排序, 排序后 [2 1 (3) 4 5 9 7 6 10 8 ] 对数组 [2 1 ] 排序, 排序后 [1 (2) 3 4 5 9 7 6 10 8 ] 对数组 [3 4 ] 排序, 排序后 [1 2 (3) 4 5 9 7 6 10 8 ] 对数组 [9 7 6 10 8 ] 排序, 排序后 [1 2 3 4 5 8 7 6 10 (9) ] 对数组 [8 7 6 ] 排序, 排序后 [1 2 3 4 5 6 7 (8) 10 9 ] 对数组 [6 7 ] 排序, 排序后 [1 2 3 4 5 (6) 7 8 10 9 ] 对数组 [10 9 ] 排序, 排序后 [1 2 3 4 5 6 7 8 9 (10) ]
数组有n个元素,由于要递归运算,算出支点pivot的位置,而后递归调用左半部分和有半部分,这个时候理解上是若第一层的话就是n/二、n/2,如果第二层就是n/四、n/四、n/四、n/4这四部分,即n个元素理解上是一共有几层2^k=n,k=log2(n),而后每层都是n的复杂度,那么平均就是O(nlog2 n)的时间复杂度。但这种确定是平均状况,若是你是标准排序的状况下,若是已是升序的顺序,那么递归只存在右半部分了,左半部分都被淘汰了。(n-1)(n-2)....*1,这个复杂度确定就是O(n^2)。
快排的实现是递归调用的, 并且每次函数调用中只使用了常数的空间,所以空间复杂度等于递归深度。
最好的状况最多须要O(log2 n)次的嵌套递归调用,因此它须要O(log2 n)的空间。最坏状况下须要O(n)次嵌套递归调用,所以须要O(n)的空间。
时间复杂度引用自知乎