近日在学习算法过程中总处在学了就忘的尴尬状态中,遂利用博客来记录学习心得。今天来和大家分享一下我对快速排序的感悟。
首先,目录如下:
- 快速排序的原理
- 快速排序的代码实现
- 快速排序的分析与感悟
- 快速排序的优化
原理:
通过每次设置基准将要排序的数组分成两部分,即大于基准的和小于基准的。再在大于基准的一部分中拿取一个作为基准,与上一步一样,将此部分分为两部分,依次进行……
算法实现:
通过算法的原理,我们来开始敲代码。(以Java为例),一看原理介绍中有绝对多步相同操作。我们容易想到了 循环和递归 ,那到底是用循环可以还是递归可以呢?抑或是两者都行,那哪种更为优越呢?先撇在这个问题,我们先想跳出条件,无论是循环还是递归,都需要一个条件来结束、跳出。我们易想到原理中说的每次分成两部分,哪些数可以有机会分成两部分?当然是此部分长度大于1了,那跳出条件就出来了
//1,找到算法的出口,其中low表示这部分的左下标,high表示这部分的右下标
if( low >= high) {
return;
}
然后,我们就要制定基准了,基准的选择便是待会优化算法的基础。现在我们为了方便,将基准选择为a[low],通过基准将一生二。选整上代码
private static void quickSort(int[] a, int low, int high) {
//1,找到递归算法的出口
if( low >= high) {
return;
}
//2,存下标
int i = low;
int j = high;
//3,key 基准
int key = a[low];
//4,完成一趟排序
while(i<j) {
//4.1,从右往左找到第一个小于key的数
while( i<j && a[j] > key){
j--;
}
// 4.2,从左往右找到第一个大于key的数
while( i<j && a[i] <= key) {
i++;
}
//4.3,交换
if(i<j) {
int p = a[i];
a[i] = a[j];
a[j] = p;
}
}
// 4.4,调整key的位置
int p = a[i];
a[i] = a[low];
a[low] = p;
//5,对key左边的数快排
quickSort(a, low, i-1 );
//6,对key右边的数快排
quickSort(a, i+1, high);
}
从两端比较这很容易理解,为什么先从右往左找到第一个小于key的数,而不是先从左往右找到第一个大于key的数,抑或是说两者谁在前都一样?以一个整型数组int a[]= {2,1,4,5,7,6,3}, 为例。第一次排序以2作为基准,要是从右边先的话,找到的第一个小于key的数为1,那左边再找第一个大于key的数时,由于i < j,左边下标 i 停留在 1 ,也就是交换了数字 2 和 1(数组下标 0 和 1) ,这样没问题。要是反过来呢?先从左往右找到第一个大于key的数,找到第一个大于基准的数字为 4 (下标为 2 ),再从右往左找到第一个小于key的数,由于i < j,右边下标 j 停留在 4 ,也就是交换了数字 2 和 4(数组下标 0 和 2) ,第一次遍历结果为:4 1 2 5 7 6 3 ,不满足条件。原因何在呢?因为我们将基准选择为a[low]。
附上整体代码:
public class QuickSort {
public static void main(String[] args) {
int a[] = {2,1,4,5,7,6,3};
System.out.println(Arrays.toString(a));
quickSort(a);
System.out.println(Arrays.toString(a));
}
public static void quickSort(int[] a) {
if(a.length>0) {
quickSort(a,0,a.length-1);
}
}
private static void quickSort(int[] a, int low, int high) {
//1,找到递归算法的出口
if( low >= high) {
return;
}
//2,存下标
int i = low;
int j = high;
//3,key 基准
int key = a[low];
//4,完成一趟排序
while(i<j) {
//4.1,从右往左找到第一个小于key的数
while( i<j && a[j] > key){
j--;
}
// 4.2,从左往右找到第一个大于key的数
while( i<j && a[i] <= key) {
i++;
}
//4.3,交换
if(i<j) {
int p = a[i];
a[i] = a[j];
a[j] = p;
}
}
// 4.4,调整key的位置
int p = a[i];
a[i] = a[low];
a[low] = p;
//5,对key左边的数快排
quickSort(a, low, i-1 );
//6,对key右边的数快排
quickSort(a, i+1, high);
}
}