正确代码
正确代码是这样的:
(升序进行说明)
public static void quickSort(int[] array, int left, int right){
//递归结束条件
if(left > right) {
return;
}
//左端基准值
int base = array[left];
int i = left, j = right;
while(i != j) {
//从右端开始查找
while(array[j] >= base && i < j) {
j--;
}
//从左端开始查找
while(array[i] <= base && i < j) {
i++;
}
//若是因为找到符合调换条件的值就调换
if(i < j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
array[left] = array[i];
array[i] = base;
quickSort(array, left, i - 1);
quickSort(array, i + 1, right);
}
问题
那么为什么把
//从右端开始查找
while(array[j] >= base && i < j) {
j--;
}
//从左端开始查找
while(array[i] <= base && i < j) {
i++;
}
改成:
//从左端开始查找
while(array[i] <= base && i < j) {
i++;
}
//从右端开始查找
while(array[j] >= base && i < j) {
j--;
}
就不对?
原因
实际上跟我们的
//左端基准值
int base = array[left];
有关。
应该是这样的:
左端基准值要从右边开始查找
右端基准值要从左边开始查找
原因(升序和左基准为例):
在快排时,当两头的索引遇见时,相遇点对应的值就会和基准点进行数据交换。我们要知道:
在进行基准点数据交换后要满足两个条件:
- 相遇点左边都要比基准值小
- 相遇点右边都要比基准值大
若从左边先开始,那么左端停止的值一定是比基准值大的值或整体停止值,若停止值也同样是比基准大的值,那么该值不会被交换到右边,只会和基准值进行交换,所以就被放在了左边,进行下一轮新的排序,并且永远不会参与进相遇值右边的排序中,就导致了一些较大的值存在了左边。
举个例子:
例子 : 7 3 2 8 9
像这样:基准值:7 。若左边开始就会停止在8的位置,右边以i==j被迫停止,7和8交换,造成
一次排序结果: 8 3 2 7 9
在进行下一次递归时:8 3 2 被分成新的快排组合,9自己被分成快排组合
那么从此 8 就走向了不归路
若是从右边开始相遇值必须停止或者是比基准值小的值,当该值是小于基准值同时为相遇值就会和基准值交换,此时该值刚好是比基准值小的值,所以符合。
右边开始从根本上避免了:左边遇见比基准值大的值,右边却无与此值交换的值