基本思想
快速排序(Quicksort)是对冒泡排序的一种改进。
通俗来说就是每次都找到一个基准点,将待排序的数据以基准点划分为两个部分,左边准存放比基准点小的数据,右边存放比基准点大的数据,这样就能够把一个数组分为两部分,通过递归的方式再将两部分的数组继续以该方式进行划分,直到每一组都只剩下一个元素即可完成排序。
动画演示
快速排序示例
java代码:
package com.stu.algorithm.sort;
import java.util.Arrays;
import java.util.Random;
/**
* @version:
* @author: 零乘一
* @description: 快排
* @date: 2021/10/6 19:57
**/
public class Quick {
public static void main(String[] args) {
int a[] = {8,4,5,7,1,3,6,2};
sort(a);
System.out.println(Arrays.toString(a));
}
public static void sort(int[] a){
int l = 0;
int r = a.length-1;
sort(a,l, r);
}
public static void sort(int[] a, int l, int r){
if (l>=r){
return;
}
//对a数组中,从l到r的元素进行切分
int partition = partition(a,l,r);
//对左边分组中的元素进行排序
sort(a,l,partition-1);
//对右边分组中的元素进行排序
sort(a,partition+1,r);
}
public static int partition(int[] a, int l, int r){
//把左边的元素当作基准值
int key = a[l];
//定义一个左侧指针,初值指向最左边的元素
int left = l;
//定义一个右侧指针,初值指向右侧的元素下一个位置
int right = r+1;
//进行切分
while (true){
while (key<a[--right]){
if (right<=l){
//已经扫描到最左边了,无需继续扫描
break;
}
}
while (key>a[++left]){
if (left>=r){
//已经扫描到最右边,无需继续扫描
break;
}
}
if (left>=right){
//扫描完了所以元素,结束循环
break;
}else {
//交换left和right索引处的元素
int temp = a[left];
a[left] = a[right];
a[right] = temp;
}
}
//交换最后right索引处和基准值所在的索引处的值
int temp = a[l];
a[l] = a[right];
a[right] = temp;
return right;
}
}
/*
测试数据:
int a[] = {8,4,5,7,1,3,6,2};
sort(a);
System.out.println(Arrays.toString(a));
*/
代码解析
找到将数组分为两部分的那个基点的位置。
找到左边的部分大于基准的元素的位置,确定下来
找到右边的部分小于基准的元素的位置,确定下来
将这两元素的位置进行交换(因为要将大于基点的元素全部都放在基准的右边,要将小于基点的元素全部都放在基准的左边)
将目前右指针指向的那个位置的元素,与基准的元素进行交换(确定基准点的位置)
为什么这里不可以是left,因为基准点本身就属于left部分的元素,所以应该right的元素进行交换,再者因为left并不一定与right在同一个位置上,有可能是在right的下一个位置(在判断左边元素是否大于基准点的那个循环中能够可看出),所以此处是right。
时间复杂度
最好的情况:O(nlogn)
每次找到的那个元素都恰好能将整个数组对半分。
最坏的情况:O(n²)
每次的基准是所有元素中最大的那个元素,因此其它所有的元素都会放在这个元素的左边的位置。