思想
假 设 数 组 的 某 个 数 作 为 基 准 , 我 们 将 比 基 准 小 的 数 放 置 在 基 准 的 左 侧 , 比 基 准 大 的 数 放 在 基 准 的 右 侧 。 假设数组的某个数作为基准,我们将比基准小的数放置在基准的左侧,比基准大的数放在基准的右侧。 假设数组的某个数作为基准,我们将比基准小的数放置在基准的左侧,比基准大的数放在基准的右侧。
我 们 通 过 分 治 , 将 基 准 的 左 侧 部 分 和 右 侧 部 分 分 为 两 个 小 数 组 进 行 如 上 操 作 , 直 到 数 组 长 度 为 1 。 我们通过分治,将基准的左侧部分和右侧部分分为两个小数组进行如上操作,直到数组长度为1。 我们通过分治,将基准的左侧部分和右侧部分分为两个小数组进行如上操作,直到数组长度为1。 这 样 就 可 以 将 所 有 的 数 都 进 行 如 上 的 操 作 , 我 们 便 可 以 得 到 一 个 有 序 数 组 。 这样就可以将所有的数都进行如上的操作,我们便可以得到一个有序数组。 这样就可以将所有的数都进行如上的操作,我们便可以得到一个有序数组。
图解
取自网络
代码模板
public void get() {
int[] arr = new int[]{3, 4, 5, 2, 1, 7, -1, 9, 0};
quickSort(arr, 0, arr.length - 1);
for (int i : arr) {
System.out.println(i);
}
}
public void quickSort(int[] arr, int left, int right) {
//结束条件:当左右指针指向同一位置时,意味着区间长度为1,无需找基准,挖坑填数,直接返回即可
if (left >= right) return;
//获取当前区间的第一个值的索引,和最后一个值的索引
int i = left, j = right;
//首先获取当前区间的第一个值(具体获取哪个值做基准,将影响快排效率),此时arr[i]成为了坑
int tmp = arr[i];
//左右挖坑填数,循环接替,直到所有比基准小的数放置基准的左侧,比它大的数放置在它的右侧
//当左右指针相遇意味着,我们已经将所有的数都与基准比较过了,结束循环
while (i < j) {
//因为现在arr[i]是坑,我们先从右指针指向的值开始,
//若比基准大,右指针向左移动
while (i < j && tmp < arr[j]) {
j--;
}
//否则把arr[j]填入arr[i]中,此时arr[j]成为了坑
if (i < j) {
arr[i] = arr[j];
i++;
}
//因为现在arr[j]是坑,我们则从左指针指向的值开始,
//若比基准小,左指针向右移动
while (i < j && tmp > arr[i]) {
i++;
}
//否则把arr[i]填入arr[j]中,此时arr[i]成为了坑
if (i < j) {
arr[j] = arr[i];
j--;
}
}
//不要忘了,把基准填入最后的坑中
arr[i] = tmp;
//分治
//通过以上的操作,基准的位置不会变了
//但基准的左侧和右侧的数还处于无序的状态
//我们通过分治递归的方法,遍历所有的数,将所有的数都找到其对应的位置
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
- 需注意的一点是:我们必须时刻监控左右指针的位置,放置出现
i>j
时,却依旧进行挖坑填数操作。
快 速 排 序 : 时 间 复 杂 度 O ( n l o g n ) 、 空 间 复 杂 度 O ( l o g n ) 快速排序:时间复杂度O(nlogn)、空间复杂度O(logn) 快速排序:时间复杂度O(nlogn)、空间复杂度O(logn)