一、快速排序算法
快速排序的基本思想如下:
- 从数组中取出一个数作为中轴数(pivot)
- 划分数组:将比这个数大的数放到它的右边,小于或等于它的数放到它的左边
- 再对左右区间重复上述步骤,直到各区间只有一个数
本篇文章实现快速排序算法的主要思路是:
1) 定义两个前向指针i,j,i记录小于中轴数的分区,通过指针j遍历数组,并将每个j位置的元素和pivot(中轴数)进行比较,arr[j] 小于 pivot 时,将arr[j]和arr[i] 交换位置,否则j直接后移继续下一个元素的遍历;
2) 最后将pivot和i-1位置(i前面的元素都小于中轴数)的数据交换;
3) 递归。
二、实例排序分析
样本数据:{5,8,4,3,2,5,7,9}
- 中轴数pivot: 一般取待排序序列的第一个(当然这个数可以选一个能让数组均匀分布的数)
- 目标: 交换后, 中轴数左边的数要全部小于中轴数, 其右边的数要全部大于等于中轴数
步骤如下: - 定义两个指针 i,j,从中轴数后一位开始,即start+1的位置;
- 通过j对数组进行循环遍历,并每次和中轴数比较,小于中轴数则将arr[j] 和arr[i]数据交换,同时i++,指向后一位置;大于中轴数则继续下一个元素比较;
- 如第一次遍历比较后(8>5),只对j后移
第二次比较后(4<5),4和8交换位置,同时i++,j++:
第一轮循环遍历后的结果如下:
此时将start位置的pivot和i-1位置的数据交换:
- 至此,以中轴数分为3部分,左边的都比其小,右边的都比其大。
对于左右两部分数据再通过递归分别进行快速排序。
三、算法实现
实现代码如下:
/**
* 两个先后指针实现快排
*/
public class QuickSort {
public void sort(int[] arr) {
if(arr == null || arr.length <= 1) {
return;
}
sortHelper(arr, 0, arr.length-1);
}
private void sortHelper(int[] arr, int start, int end) {
if(start >= end){
return;
}
// 分治
int middle = partition(arr, start, end);
// 左右部分进行递归
sortHelper(arr, start, middle - 1);
sortHelper(arr, middle+1, end);
}
private int partition(int[] arr, int start, int end) {
// 选一个中轴数 pivot, 一般选第一个数即可
int pivot = arr[start];
int i = start + 1; // 从第二个数开始循环比较
for(int j=start+1; j <= end; j++){
if(arr[j] < pivot){
swap(arr, i, j);
i++;
}
printArray(arr);
}
// 第i 个数为大于pivot 的数, 将pivot 和i 的前一位置交换
swap(arr, start, i-1);
// 返回pivot位置
return i-1;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 数组打印
* @param arr
*/
public static void printArray(int arr[]) {
int n = arr.length;
for (int i=0; i<n; ++i)
System.out.print(arr[i] + " ");
System.out.println();
}
public static void main(String[] args) {
int[] arrayToSort = {5,8,4,3,2,5,7,9};
printArray(arrayToSort);
int[] arrayClone = Arrays.copyOf(arrayToSort, arrayToSort.length);
Sorter sorter = new QuickSort();
sorter.sort(arrayToSort);
printArray(arrayToSort);
// jdk 排序
Arrays.sort(arrayClone);
System.out.println("jdk Arrays.sort排序结果:");
printArray(arrayClone);
}
}
运行结果:
5 8 4 3 2 5 7 9
5 8 4 3 2 5 7 9
5 4 8 3 2 5 7 9
5 4 3 8 2 5 7 9
5 4 3 2 8 5 7 9
5 4 3 2 8 5 7 9
5 4 3 2 8 5 7 9
5 4 3 2 8 5 7 9
2 4 3 5 8 5 7 9
2 4 3 5 8 5 7 9
2 4 3 5 8 5 7 9
2 3 4 5 8 5 7 9
2 3 4 5 8 5 7 9
2 3 4 5 8 5 7 9
2 3 4 5 7 5 8 9
排序结果:
2 3 4 5 5 7 8 9
jdk 排序结果:
2 3 4 5 5 7 8 9
由于快排需要交换元素顺序,不保证相同元素的起始先后顺序,所以快排是不稳定排序。
注: 快速排序的最好的情况(每次数据划分得很均匀)时间复杂度为O(nlogn),最坏的情况(需排序的数据为正序或逆序排列时)复杂度为O(n^2)。