概述
执行流程:
- 从序列中选择一个轴点元素(pivot)。假设每次选择第一个位置的元素为轴点元素;
- 利用pivot将序列分割成2个子序列 。 将小于pivot的元素放到pivot前面(左侧);将大于pivot的元素放到pivot后面(右侧);等于pivot的元素放到哪都可以;
- 对子序列进行1、2操作。直到不能再分割(子序列中只剩下一个元素);
案列图:
快速排序的大致思想我们了解了,关键是我们怎么构建轴点呢?
轴点构造:
- 一般选取数组的第一个元素作为轴点元素(pivot)
- 将轴点元素(pivot)备份一份,后面会用
- begin表示坐标,初始值是轴点坐标;end表示坐标,初始值是最后元素下标;
- 从右向左开始检索。如果end坐标的元素大于轴点元素,则不用动,end–;检索下一个end,如果end坐标元素小于轴点元素,则将end元素赋值给begin坐标(因为之前pivot已经备份了,所以不会造成数据丢失),然后让begin++,开始从左向右检索
- 从左向右开始检索。如果begin坐标的元素小于轴点元素,则不用动,begin++;检索下一个begin,如果begin坐标元素大于轴点元素,则将begin元素赋值给end坐标,然后让end–,开始从右向左检索
- 重复 4、5 操作直到begin==end
- 最后找到的轴点下标就是begin
代码实现:
package 排序算法;
public class 快速排序 {
public static void main(String[] args) {
int[] arr = {0,9,8,6,5,7,3,1,2,4,0,10,11,12,13,15};
System.out.println("排序前:");
for(int i: arr){
System.out.print(i+" ");
}
sort(arr, 0, arr.length-1);
System.out.println();
System.out.println("排序后:");
for(int i: arr){
System.out.print(i+" ");
}
}
/**
* 快速排序算法 (sort + pivotIndex)
* @param arr
* @param begin
* @param end
*/
// 核心逻辑
public static void sort(int[] arr, int begin, int end) {
if (end - begin <= 0) return; // 终止条件是,序列只剩下一个元素
// 确定轴点的位置
int mid = pivotIndex(arr, begin, end);
// 对子序列进行排序
sort(arr, begin, mid-1);
sort(arr, mid+1, end);
}
// 找到中心轴
public static int pivotIndex(int[] arr, int begin, int end) {
// 备份begin下标的元素,作为中心轴元素
int pivot = arr[begin];
while (begin<end) { // 循环条件是begin<end,如果begin=end说明找到了中心轴,退出循环
/**
* 从右向左开始检索
*/
while (begin<end && arr[end]>pivot) { // 如果begin<end且end下标的值大于pivot,则不发生交换,用下个end与pivot比较
end--;
}
if (begin<end) { // 进入这个代码块说明 arr[end]<=pivot
arr[begin] = arr[end]; // 让end元素赋值给begin元素(初始时,已经备份了arr[begin],因此不会造成数据丢失)
begin++; // 勿忘让begin++,开始从左向右检索
}
/**
* 从左向右开始检索,这里逻辑跟上面类似,我就不做注释了
*/
while (begin<end && arr[begin]<pivot) {
begin++;
}
if (begin<end) {
arr[end] = arr[begin];
end--;
}
/**
* 如果begin=end说明找到了中心轴,退出循环
*/
if (begin==end) {
arr[begin] = pivot;
}
}
return begin; // 返回中心轴坐标
}
}