快速排序
简述
快速排序使用分治法(Divide and conquer)策略,
来把一个串行(list)分为两个子串行(sub-lists)。
本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。
步骤:
1,从数列中挑出一个元素,称为 “基准”(pivot);
2,重新排序数列,所有元素比基准值小的摆放在基准前面,
所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
3,递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
时间复杂度
在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。
在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。
事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
核心代码
//3,测试
public static void main(String[] args) {
int[] arr = { 49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22 };
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
//排序
quickSort(arr, 0, arr.length - 1);
System.out.println("排序后:");
System.out.println(Arrays.toString(arr));
/*
测试结果
排序前:
[49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22]
排序后:
[-1, 0, 1, 2, 5, 8, 22, 22, 23, 38, 49, 65, 76, 97]
*/
}
//1,递归快排
public static void quickSort(int[] arr,int left,int right){
if (left < right) {
// 找寻基准数据的正确索引--基准点
int index = getIndex(arr, left, right);
// 进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
quickSort(arr, left, index - 1);
quickSort(arr, index + 1, right);
}
}
//2,找基准点
public static int getIndex(int[] arr, int left, int right) {
//设置一个基准数据(这里始终将left位置的元素设置为基准数据,方便,也可以选right,效果一样)
int key = arr[left];
// 记录 left的下标 用于找到基准点后,通过下标 交换 left和基准点处的元素 的数据
int index=left;
// 左右向中间逼近
// 1)左left向右移动,直到找到比基准数据大的数停止(情况1-1) 或 左left和右right重合时停止(情况2-1:left++导致)
// 2)右right向左移动,直到找到比基准数据小的数停止(情况1-2) 或 右right和左left重合时停止(情况2-2:right++导致)
// 当左left和右right都停止--情况1,说明同时找到了左边比基准数据大的元素以及右边比基准数据小的元素,此时两个元素相互调换数据
// 当左left和右right都停止--情况2,说明左left和右right重合了,此时的 left/right 就是要找的基准点
while (left < right) {
while (key <= arr[right] && left < right) {
right--;
}
while (key >= arr[left] && left < right) {
left++;
}
if (left < right) {
arr[left] = arr[left] ^ arr[right];
arr[right] = arr[left] ^ arr[right];
arr[left] = arr[left] ^ arr[right];
}
}
//此时left==right --找到基准点
//交换 index(原left)和基准点处的元素 的数据
arr[index]=arr[left];
arr[left]=key;
return left;
}