目录
1. 快速排序原理介绍
快速排序是一种不稳定的排序算法,它的时间复杂度是O(N*logN),快速排序的基本思想是:每次从待排序的序列中选出一个基准数/枢轴(英文称为pivot),然后比它小的数都放到它的左边,比它大的数都放到它的右边,然后再对pivot的左边和右边两个序列进行快速排序,当排序的序列中只有一个数时不需要进行排序,此时排序已经完成。这里也有用到一种“分治思想”
举个例子:假设现在有一个序列:[33, 27, 41, 26, 78, 19, 52, 81],首先取第一个元素作为枢轴:pivot = 33,对整个序列进行快速排序,排序后的结果为:[19, 27, 26, 33, 78, 41, 52, 81],可以看到以33为pivot的第一轮排序后,比它小的元素全部位于33的左边,比它大的元素全部位于33的右边,此时我们再对左右两边的序列:[19, 27, 26]和[78, 41, 52, 81]进行快速排序(分治),同样取每个序列的第一个元素作为枢轴······直至序列只有一个元素时,此时整个序列已经有序。
因为快速排序的效率非常高,而且掌握它也有一定的难度,所以各大企业都会拿这个来考察程序员,通常上来就让你写一个快速排序给他过目,掌握这个排序真的已经是企业的基础了,也是考察一个程序员基础的重要指标之一了。
2. 快速排序算法步骤
现在有一个待排序的序列:[33, 27, 41, 26, 78, 19, 52, 81],使用快速排序算法进行排序,我会以第一轮排序为例演示快速排序的整个流程。
我假定每次排序都取第一个数为基准数(pivot),则第一轮排序pivot = 33,由于33被pivot这个变量存储,所以我们可以认为index = 0的位置是挖空出来的,可以放数据进去,也就是下图中的红色区域。然后使用两个指针left和right分别指向序列的首部和尾部。初始化left = 0,right = 7
【下图中的前三行】(1)从后往前扫描元素,找到第一个小于pivot的元素,找到下标right = 5的元素满足条件(19 < 33),插入到当前的空闲位置(left = 0),则arr[left] = arr[right] 即 arr[0] = arr[5] = 19,而此时空闲位置由 left = 0 转化为 right = 5。将左指针left++(left = 1)
【下图中的第四五行】(2)从前往后扫描元素,找到第一个大于pivot的元素, 找到下标left = 2的元素满足条件(41 > 33),插入到当前的空闲位置(right = 5),则arr[right] = arr[left] 即 arr[5] = arr[2] = 41,空闲位置由right = 5转化为left = 2。将右指针right--(right = 4)
【下图中的第六行】(3)从后往前扫描元素,找到下标right = 3的元素满足条件(26 < 33),插入到当前空闲位置(left = 2),则arr[left] = arr[right] 即 arr[2] = arr[3] = 26,空闲位置由left = 2转化为right = 3。将指针left++(left = 3)
【下图中的第七行】(4)从前往后扫描元素,此时 left = right,代表所有元素都已经与pivot比较过,换言之所有需要交换位置的元素都已经交换完毕,所以最后将pivot填到最后的空闲位置(left = right = 3)即arr[left]/arr[right] = pivot 即 arr[3] = 33,此时第一轮排序完成,进行下一轮的快速排序(重复这四个步骤)
3. 代码实现
/**
* @author Zeng
* @date 2020/3/2 9:09
*/
public class QuickSort {
public static void main(String[] args) {
int[] arr = new int[]{33, 27, 41, 26, 78, 19, 52, 81};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr, int begin, int end) {
if (begin < end) {
//以第一个数作为基准数
int pivot = arr[begin];
//左指针,找到比基准数大的元素
int left = begin;
//右指针,找到比基准数小的元素
int right = end;
while (left < right) {
//从后往前找到第一个比pivot小的元素
while (left < right && arr[right] >= pivot) {
right--;
}
//将元素填到空闲位置
if (left < right) {
arr[left] = arr[right];
left++;
}
//从前往后找到第一个比pivot大的元素
while (left < right && arr[left] < pivot) {
left++;
}
//将元素填到空闲位置
if (left < right) {
arr[right] = arr[left];
right--;
}
//回填pivot
if (left == right) {
arr[left] = pivot;
}
//对pivot左边的序列进行快速排序
quickSort(arr, begin, left - 1);
//对pivot右边的序列进行快速排序
quickSort(arr, left + 1, end);
}
}
}
}
//[19, 26, 27, 33, 41, 52, 78, 81]