快速排序是冒泡排序的改进版,也是最好的一种排序,涉及到分治和递归。
冒泡排序中记录的比较和交换在相邻的单元中进行,每次交换只能上移或者下移一个单元,因而总的比较和移动次数较多(O(n2))
快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
该方法的基本思想是:
1.先从一个数列中取出一个数作为基准数(简单起见可以取第一个数)
2.分区过程,将比这个数大的全部放在它的右边,小于等于的放在它的左边(分区
)
3.再对左右区间重复第一步和第二部,直到区间只有一个数(递归
)
第一趟排序
初始状态:10个数
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
指定起始坐标i=0,终了坐标j=9,假设第一个数72为基准数
,把72挖出来,空出位置
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
- | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 | 72 | |
i=0 | j=9 | x |
从右向左移动,找到第一个小于72的数48(j=8)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
- | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 | 72 | |
i=0 | j=8 | x |
将48填入到i=0的位置,i++等于1,j=8成为“坑”
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 85 | 72 | ||
i=1 | j=8 | x |
从左向右移动,找到第一个大于72的数88(i=3)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 85 | 72 | ||
i=3 | j=8 | x |
将88填入到j=8的位置,j–等于7,i=3成为“坑”
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 60 | 42 | 83 | 73 | 88 | 85 | 72 | ||
i=3 | j=7 | x |
从右向左移动,找到第一个小于72的数42(j=5)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 60 | 42 | 83 | 73 | 88 | 85 | 72 | ||
i=3 | j=5 | x |
将42填入到i=3的位置,i++等于4,j=5成为“坑”
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 42 | 60 | 83 | 73 | 88 | 85 | 72 | ||
i=4 | j=5 | x |
从左向右移动i,找到第一个大于等于72的值,找到坑(i=j)也没找到,循环结束。说明左边全部小于72,右边全部大于等于72
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 42 | 60 | 83 | 73 | 88 | 85 | 72 | ||
i=4 j=5 | x |
将基准值72填入i=j的坑内。前部分小于72,后部分大于72,第一趟排序结束
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | - | - |
---|---|---|---|---|---|---|---|---|---|---|---|
48 | 6 | 57 | 42 | 60 | 72 | 83 | 73 | 88 | 85 | 72 | |
i=4 j=5 | x |
对前后两个分区重复刚才的步骤(递归
),完成排序
快速排序=冒泡+分治+递归
快速排序的过程:东拆西补,西拆东补或一边拆一边补
/**
* 快速排序算法
*
* @author chenc
* @create 2019-09-15 14:25
**/
public class QuickSort {
public static void main(String[] args) {
// 1.给出无序数组
int[] arry = {72, 6, 57, 88, 60, 42, 83, 73, 48, 85};
// 2.输出无序数组
System.out.println(Arrays.toString(arry));
// 3.快速排序
quickSort(arry);
// 4.输出排序后数组
System.out.println(Arrays.toString(arry));
}
/**
* 快速排序
*
* @param arry 排序数组
*/
public static void quickSort(int[] arry) {
// 默认起始位置为低位索引
int low = 0;
// 默认最后位置为高位索引
int high = arry.length - 1;
quickSort(arry, low, high);
}
/**
* 快速排序(分区+递归)
*
* @param arry 数组
* @param low 低位索引
* @param high 高位索引
*/
private static void quickSort(int[] arry, int low, int high) {
if (low >= high) {
return;
}
// 分区操作,将一个数组分成两个分区,返回分区界限索引
int index = partition(arry, low, high);
// 对左分区进行快速排序
quickSort(arry, low, index - 1);
// 对右分区进行快速排序
quickSort(arry, index + 1, high);
}
/**
* 分区操作
*
* @param arry 数组
* @param low 低位索引
* @param high 高位索引
* @return 基准值索引
*/
private static int partition(int[] arry, int low, int high) {
// 指定左指针和右指针
int i = low;
int j = high;
// 确定基准数:默认数组第一个
//int baseIndex = low;
int x = arry[low];
// 使用循环进行分区操作
while (i < j) {
// 1.从右向左移动指针j,找到第一个小于基准值得数arry[j]
while (arry[j] >= x && i < j) {
j--;
}
// 2.将右侧找到的数放入左边的坑中,左指针向中间移动一位i++
if (i < j) {
arry[i] = arry[j];
i++;
}
// 3.从左向右移动指针i,找到第一个大于基准值得数arry[j]
while (arry[i] < x && i < j) {
i++;
}
// 4.将左侧找到的数放入右边的坑中,右指针向中间移动一位j--
if (i < j) {
arry[j] = arry[i];
j--;
}
}
// 使用基准值填坑
arry[i] = x;
return i;
}
}