取中间的元素s作比较,同样的先得往右找比s大的索引 i,然后往左找比s小的索引 j,只要两边的索引还没有交叉(也就i=j),就交换 i 与 j 的元素值。这里不用再进行轴的交换,因为在寻找交换的过程中,轴位置的元素也会参与交换的动作,轴已经成为一个抽象的概念,代表的是一个数值而已。
有比较,才有进步,才能更清晰地认识事物。下面是两种算法代码差异比较:
[b]1, 轴的选定:[/b]
[b]2, 左边界的赋值[/b]
[b]3, 比较的不同[/b]
[b]4, 递归的不同[/b]
小结:撇开效率,仅从代码精简来说,也应该考虑V2,何况V2少了判断与移动轴,效率更高!
public static void QuickSort(int[] number)
{
QuickSort(number, 0, number.length - 1);
}
/**
* 将轴设定为中间的元素,依这个元素作基准进行比较,这可以增加快速排序法的效率
* @param number 待排序数组
* @param left 最小index
* @param right 最大index
*/
private static void QuickSort(int[] number, int left, int right)
{
if (left < right)
{
int s = number[(left + right) / 2];
int i = left - 1;//中间元素作为基准,从0开始比较
int j = right + 1;
while (true)
{
// 1. 令索引 i 从数组左方往右方找,直到找到大于(不小于) s 的数的索引
while (number[++i] < s){}
// 2. 令索引 j 从数组右方往左方找,直到找到小于(不大于) s 的数的索引
while (number[--j] > s){}
// 3. 如果 i >= j,则退出循环
if (i >= j) break;
// 4. 如果 i < j,则交换索引i与j两处的值
swap(number, i, j);
}
// 5. 对轴左边进行递归
QuickSort(number, left, i - 1);
// 6. 对轴右边进行递归
QuickSort(number, j + 1, right);
}
}
private static void swap(int[] number, int i, int j)
{
int t;
t = number[i];
number[i] = number[j];
number[j] = t;
}
有比较,才有进步,才能更清晰地认识事物。下面是两种算法代码差异比较:
[b]1, 轴的选定:[/b]
int s = number[left];//V1:将最左边的数设定为轴,并记录其值为 s
int s = number[(left + right) / 2];//V2:中间元素作为基准
[b]2, 左边界的赋值[/b]
int i = left;//V1:轴在左边,比较该从index为1的地方开始,参考3
int i = left - 1;//V2:轴在中间,比较该从index为0的地方开始,参考3
[b]3, 比较的不同[/b]
while (i + 1 < number.length && number[++i] < s){}
while (j - 1 >= 0 && number[--j] > s) {}
//V1:对i, j进行了越界判断
while (number[++i] < s){}
while (number[--j] > s){}
/*V2:未对i, j进行了越界判断。当number[i]<s的时候循环继续,而s在中间,如果s左边的数都比s小,循环到number[i]=s的时候,s !< s,条件不成立,退出循环。i或者j为s的下标。所以不需要判断。对于V1,因为总是从边界的下一个数开始比较,当左右边界已经靠近时就有可能发生ArrayIndexOutOfBoundsException异常。所以要判断!*/
[b]4, 递归的不同[/b]
quicksort(number, left, j - 1);
quicksort(number, j + 1, right);
//V1:因为将新的轴在j处交换,所以递归与j相关
QuickSort(number, left, i - 1);
QuickSort(number, j + 1, right);
//V2:轴在中间,i, j的值也最多能到中间,所以递归与各自的i, j相关。
小结:撇开效率,仅从代码精简来说,也应该考虑V2,何况V2少了判断与移动轴,效率更高!