快速排序
原理
- 从数组中挑出1个元素,作为基准数。
- 将元素分而治之,小的移动至基准数左侧,大的移动至基准数右侧。
- 基准数两侧作为两个子数组,分别重复上述步骤。
图解分析
假设当前存在数组{12,23,67,2,34},需要对其进行快速排序,步骤如下所示:
-
先取数组第1个元素作为基准数,并声明指针I指向数组头部,指针J指向数组尾部。
-
从右往左移动指针J,找出第1个小于基准数的值。
- 从左往右移动指针I,找出第1个大于基准数的值,并将其与指针J所指数值进行交换。
-
交换后,按照1、2步骤依次移动指针J和指针I。
若指针IJ重叠时,则移动结束,此时将指针IJ共同指向元素与基准数进行交换。
经过步骤4后,我们可以得到以下结果:基准数元素(指针IJ共同指向元素)将数组切分为2个子数组,左侧子数组的元素均小于基准数,右侧子数组的元素均大于基准数。
接下来我们将切分出来的2个子数组分别重复1~4步骤,直到子数组无法再继续拆分(例如:左侧子数组仅剩1个元素,无法进行拆分),这样我们便完成了数组的排序。
代码实现
public class QuickSort {
public static void sort(int[] arr, int low, int high) {
// 跳出递归条件
if (low >= high) {
return;
}
int standard = arr[low]; // 基准数
int i = low;
int j = high;
while (i < j) {
// 从右往左, 筛选出小于基准数元素的位置
while (standard <= arr[j] && i < j) {
j--;
}
// 从左往右, 筛选出大于基准数元素的位置
while (standard >= arr[i] && i < j) {
i++;
}
// 交换位置
if (i < j) {
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
// 左右指针重合, 基准数与ij重合的元素交按
arr[low] = arr[i];
arr[i] = standard;
// 递归调用左半数组
sort(arr, low, j - 1);
// 递归调用右半数组
sort(arr, j + 1, high);
}
public static void print(int[] arr) {
System.out.print("排序结果: ");
for (int item : arr) {
System.out.print(item + " ");
}
}
public static void main(String[] args) {
int[] arr = new int[]{12, 23, 67, 2, 34};
sort(arr, 0, arr.length - 1);
print(arr);
}
}
时间复杂度
最好情况
处理过程中的每个数组,基准数正好是数组的中位数,此时时间复杂度为:O(nlogn)。
最坏情况
操作过程中的每个数组,基准数正好是数组的最大值或者最小值。例如,我们需要对n个数进行排序,每进行处理的时候,选出的基准数均是数组的最小值。于是乎,在经过调换元素顺序的操作,最小值被放在第1位,以此类推,每次操作,都只能将最小值放到第1位,而剩下的元素,则没有任何变化,此时便等价于冒泡排序,时间复杂度为:O(n^2)。