八、快速排序(Quick Sort)
1、概念
使用二分的思想,每次将排序序列分成两组。
找到中间索引元素值,依次比较两端元素值和中间索引,后移开始索引,前移结束索引,不断地向中间索引位置逼近,如果开始索引大于结束索引,则跳出循环,否则就交换两端索引值,如果两端有元素值等于中间索引值,则需要移动对端索引值。
最后判断开始索引和前移后的结束索引之间是否还有元素,如果存在,则仍需快排。同理后移后的开始索引和结束索引之间也要判断是否需要进行快排。
快速排序属于交换排序
的一种。
2、过程
- 首先定义一个排序方法,入参为排序序列、起始查找索引和终止查找索引(包括)。
- 在排序方法里先保存两端查找索引,再找到本次排序的中间元素值。使用循环判断左端查找索引小于右端查找索引。在循环内部,再使用两个循环,分别判断左端元素值是否小于(正序)中间元素值,并将左端索引位置右移,以及中间元素值是否也小于(正序)右端元素值,并将右端索引位置左移。如果左端索引位置等于或超过了右端索引位置,则跳出循环判断。否则交换两端元素值。再判断交换后的元素值是否等于中间元素值,若相等,则需要左移右端索引位置或右移左端索引位置。
- 跳出循环判断后,需要判断两端索引位置是否相等,若相等,则需要分别右移左端索引位置和左移右端索引位置。
- 最后判断右端索引位置是否大于起始查找索引位置,如果大于,则仍需要将这两个索引位置中间的排序序列进行二分快速排序。同理若存在左端索引位置到终止查找索引位置的排序序列,也需要进行二分快速排序。
3、示例
正序
public void quickSort(int[] array) {
quickSort(array, 0, array.length - 1);
}
private void quickSort(int[] array, final int begin, final int end) {
int b = begin;
int e = end;
int middle = array[(b + e) >> 1];
int temp;
while (b < e) {
while (array[b] < middle) {
b++;
}
while (middle < array[e]) {
e--;
}
if (b >= e) {
break;
}
temp = array[b];
array[b] = array[e];
array[e] = temp;
if (array[b] == middle) {
e--;
}
if (array[e] == middle) {
b++;
}
}
if (b == e) {
b++;
e--;
}
if (begin < e) {
quickSort(array, begin, e);
}
if (b < end) {
quickSort(array, b, end);
}
}
倒序
public void quickSort(int[] array) {
quickSort(array, 0, array.length - 1);
}
private void quickSort(int[] array, final int begin, final int end) {
int b = begin;
int e = end;
int middle = array[(b + e) >> 1];
int temp;
while (b < e) {
while (array[b] > middle) { // 倒序
b++;
}
while (middle > array[e]) { // 倒序
e--;
}
if (b >= e) {
break;
}
temp = array[b];
array[b] = array[e];
array[e] = temp;
if (array[b] == middle) {
e--;
}
if (array[e] == middle) {
b++;
}
}
if (b == e) {
b++;
e--;
}
if (begin < e) {
quickSort(array, begin, e);
}
if (b < end) {
quickSort(array, b, end);
}
}
4、性能
- 时间复杂度:平均时间复杂度
O(nlog₂n) 所有排序算法当中最快的
,最坏时间复杂度O(n²)
- 空间复杂度:
O(nlog₂n) 因为尾递归
- 稳定性:不稳定(a=b,排序前a在b的前面,排序后a不一定还在b的前面)