快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,而后递归地排序两个子序列。java
快排的核心思想是:将要排序的序列(假设下标是从start到end)中选任意一个数据做为pivot(分区点,也叫基准点),而后遍历数据,将小于pivot 的数据放在pivot的前面,大于等于 pivot 的数据放在pivot的后面。以后递归的将两个子序列排序。算法
过程以下。数组
这里咱们给出的是原地排序的实现,也就是算法的执行过程当中不须要额外的空间。ide
public class Quick { // 快速排序,a是数组,n表示数组的大小 public static void quickSort(int[] a, int n) { quickSortInternally(a, 0, n - 1); } // 快速排序递归函数 private static void quickSortInternally(int[] a, int start, int end) { if (start >= end) { return; } int q = partition(a, start, end); // 获取分区点 quickSortInternally(a, start, q - 1); quickSortInternally(a, q + 1, end); } }
上面的这个是递归实现的,能够看出跟归并排序的代码有点类似,这里最主要的就是分区点的获取。函数
private static int partition(int[] a, int start, int end) { int pivot = a[end]; int i = start; for (int j = start; j < end; ++j) { if (a[j] < pivot) { if (i == j) { ++i; } else { swap(a, i, j); ++i; } } } swap(a, i, end); return i; } public static void swap(int[] a, int i, int j) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; }
在这里咱们的分区点都是选择须要排列的数组的最后一个节点。下面有第一个分区点的获取步骤的演示,能够看看。ui
能够看出 i 始终指向的是数组中第一个值大于分区点的节点,j 则是遍历数组,寻找值小于分区点的节点,而后与i指向的节点交换位置,以后i++,这样当j遍历一遍数组后i左边的都是值小于分区点的,i右边都是值大于等于分区点,最后i与分区点交换位置。这样第一遍遍历就完成了。code
快排是一种原地、不稳定的算法,他的时间复杂度是 O(nlogn),相比较于归并排序,快排具备空间的优点,可是他的时间复杂度并不如归并排序那么稳定,当须要排列的数组近乎有序时,咱们仍选择最后一个元素做为分区点的话,快排的时间复杂度就变成了O(n2)了,blog