图解快速排序算法(补充)
关于快速排序算法的两种实现(split、partition)在上一篇”快速排序算法的两种Java实现及图解“中已经通过图示详细说明,并且也附上了Java代码。
但是,第二种实现方法(partition)的代码中有一点需要注意的,没有强调,并且也没有给予解释。
/**
* (6)-6.2 快速排序
* 双指针方法-partition
* @param arr
* @param low // start
* @param high // end
* @return
*/
public static int[] quickSort2(int arr[], int low, int high)
{
if(low < high)
{
int i = partition(arr, low, high); //划分数组并获取比较元素的位置
quickSort2(arr, low, i-1); //对比较元素左边进行排序
quickSort2(arr, i+1, high); //对比较元素右边进行排序
}
return arr;
}
//划分数组
public static int partition(int arr[], int low, int high)
{
int x = arr[low]; //将该数组第一个元素设置为比较元素
int i=low;
int j=high;
while(i < j)
{
while(i<j && arr[j] >= x)
j--; //从右至左找到第一个小于比较元素的数
while(i<j && arr[i] <= x)
i++; //从左至右找到第一个大于比较元素的数
/*需要注意的是,这里的j--与i++的顺序不可以调换!
*如果调换了顺序,i会走过头,以至于将后面较大的元素交换到数组开头*/
//将大数与小数交换
if(i!=j)
swap(arr, i, j);
}
swap(arr, i, low); //将比较元素交换到期望位置
return i; //返回比较元素的位置
}
//交换函数
public static void swap(int arr[], int i, int j)
{
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
NOTE:
*需要注意的是,这里的j--与i++的顺序不可以调换!
*如果调换了顺序,i会走过头,以至于将后面较大的元素交换到数组开头。
while(i<j && arr[j] >= x)
j--; //从右至左找到第一个小于比较元素的数
while(i<j && arr[i] <= x)
i++; //从左至右找到第一个大于比较元素的数
这两句话什么意思呢?为什么互换了会走过头?(请看如下图例)
拿无序数组[5,3,2,1,4,6,7] 为例:
上图这种情况就是将”i++“放在”j--“之前的后果。i走过了头,将比”基准值“(or比较元素5)更大的6交换到了数组开头!显然这种情况是我们不想看到的。
接着,看一下先移动指针 j 会有怎样的结果:
比较上边两种情况,其实对于指针 j 来说,没有”过头“的概念,即使称之为”过头“了,最终与”基准值“相交换 换到数组开头的也是一个小于”基准值“(这里<5)的元素,所以”j--“在前对结果无影响,但是若”i++“在前则会排序错误。
参考:
十大经典排序算法: https://www.jianshu.com/p/c1efd6a8bb95