基本思想:
选取一个基数(通常为第一个或者最后一个), 在一次遍历中不断的比较和交换, 把比基数小的数字都交换到基数的左部, 比基数大的都交换到右部, 然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
最好最坏时间复杂度:
最好:
快速排序最“快”的地方在于左右两边能够快速同时递归排序下去,所以最优的情况是基准值刚好取在无序区的中间,这样能够最大效率地让两边排序,同时最大地减少递归划分的次数。此时的时间复杂度仅为 O(NlogN)。
最坏:
快速排序也有存在不足的情况,当每次划分基准值时,得到的基准值总是当前无序区域里最大或最小的那个元素,这种情况下基准值的一边为空,另一边则依然存在着很多元素(仅仅比排序前少了一个),此时时间复杂度为 O(N*N)。
从上面我们可以知道, 快速排序的关键在于对 基数 的选取.
java实现
/**
* @author djh on 2019/5/28 17:34
* @E-Mail 1544579459@qq.com
*/
public class QuickSort {
public static void main(String[] args) {
int[] nums = new int[]{2, 3, 4, 5, 6, 7, 84, 1, 22, 3, 77, 442, 1, 99, 112, 908, 56};
quickSort(nums, 0, nums.length - 1);
System.out.println(Arrays.toString(nums));
}
public static void quickSort(int[] nums, int left, int right) {
if (left > right) {
return;
}
int l = left;
int r = right;
// 选取最左边的为基数.
int base = nums[left];
while (l != r) {
// 从右边开始找, 一直找到一个比基数小的数便停下来
while (r > l && nums[r] >= base) {
r--;
}
// 然后从左边开始找, 一直找到一个比基数大的数便停下来
while (l < r && nums[l] <= base) {
l++;
}
// 交换这两个变量
if (l < r) {
// 使用异或交换两个变量, 需要注意这两个变量不能相等, 不然异或后结果为 0
nums[l] ^= nums[r];
nums[r] ^= nums[l];
nums[l] ^= nums[r];
}
// 如果 left 还不等于 right, 说明还未遍历完, 进行下一次循环.
}
// 最后把基数和 l 与 r 指针相碰撞的位置的数相互交换.
// 比较迷的是为什么能确定此时 l 位置的数一定比基数小?
// 想想上面的循环过程就明白了, 我们每次在进行交换后, 此时 l 所指向的这个数一定小于等于基数,
// 然后进行下一次循环, 又不断的从右边开始找, 假设右边的数都比基数大, 那么 r 会一直走到和 l 相
// 碰撞才会停下来, 然后退出循环, 交换基数和 l 所指向的数, 所以此时 l 指向的数必定小于等于基数.
int temp = nums[left];
nums[left] = nums[l];
nums[l] = temp;
// 递归对左右两个部分分别进行排序.
quickSort(nums, left, l - 1);
quickSort(nums, l + 1, right);
}
}
输出:
[1, 1, 2, 3, 3, 4, 5, 6, 7, 22, 56, 77, 84, 99, 112, 442, 908]
Process finished with exit code 0
参考:
教你学习快速排序算法-程序员必备哦
https://blog.csdn.net/jianyuerensheng/article/details/51258374
https://blog.csdn.net/IT_ZJYANG/article/details/53406764