快速排序
快速排序(Quicksort),简称快排,是一种排序算法。在平均状况下,排序n个项目要O(n/logn)次比较。在最坏状况下则需要O(n^{2})次比较,但这种状况并不常见。事实上,快速排序通常明显比其他算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地达成。
思想
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为两个子序列(sub-lists)。
步骤为:
- 从数列中挑出一个元素,称为”基准”(pivot)。
- 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。
- 递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
递归实现
- Java
// 递归方式private void qSort(int[] arr, int head, int tail) {// 输入检查if (arr == null || arr.length <= 1 || head >= tail) {return;}int i = head, j = tail;// 取中间数为基准数int pivot = arr[(head + tail) / 2];while (i < j) {while (arr[i] < pivot) {++i;}// 这里如果加上等于符号,则会数组导致越界while (arr[j] > pivot) {--j;}if (i < j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;++i;--j;} else if (i == j) {++i;}}qSort(arr, head, j);qSort(arr, i, tail);}
循环方式
//循环方式:使用容器缓存后续需要排序的子数组索引。private void qSort2(int[] arr) {// 输入检查if (arr == null || arr.length <= 1) {return;}Stack<Integer> cache = new Stack<>();pushArrIndex(cache, 0, arr.length - 1);while (!cache.empty()) {int tail = cache.pop();int start = cache.pop();int i = start, j = tail;// 取中间数为基准数int pivot = arr[(start + tail) / 2];while (i < j) {while (arr[i] < pivot) {++i;}while (arr[j] > pivot) {--j;}if (i < j) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;++i;--j;} else if (i == j) {++i;}}if (start < j) {pushArrIndex(cache, start, j);}if (i < tail) {pushArrIndex(cache, i, tail);}}}private void pushArrIndex(Stack<Integer> stack, int start, int tail) {// 先pushstart,取出来时先取到的是endstack.push(start);stack.push(tail);
小结
快排主要思想就是分治法,常用递归解法,如果数据量大可考虑使用循环解法,避免方法栈溢出。
