声明
思路抄袭《啊哈,算法》,书写的更详细,值得一看
简易思路:
以一个数为标准,称为[基准数]
小于基准数的放左边
大于基准数的放右边
将其定为[移动规则]
移动之前
[3] 2 5 6 7 1 4
开始移动
[3] 2 5 6 7 [3] 4
以[3]为基准书,则经过第一次移动之后
1 2 [3] 6 7 5 4
第一次移动完成之后,再以基准数为边界
将其切割{1, 2} [3] {6, 7, 5, 4},
再分别对{1, 2}, {6, 7, 5, 4}进行相同规则的移动
递归行为
直到不可再切割,表示排序已完成。
具体实现
[3] 2 5 6 7 1 4
- 以[最左边]的数为基准[3]。
- 然后找两个侦察兵,从两端搜索。
[3]. 一个从右往左搜找到小于基准数的,停在那里 - 一个从左往右搜找到大于基准数的,停在那里
- 没有相遇?两个交换位置
- 相遇?切割字符串
针对切割出来的两串数组,回到1
实操
预备:
#1表示侦察兵1号,任务是找到大于基准数的数字
#2表示侦察兵2号,任务是找到小于基准数的数字
初始状态:
(#1)[3] 2 5 6 7 1 (#2)4
开始行动
(#1)[3] 2 5 6 7 1 (#2)4
#2判断:4小于[3]吗?不小,继续
(#1)[3] 2 5 6 7 (#2)1 4
#2判断:1小于[3]吗?小,停,完成任务
此时#1开始
(#1)[3] 2 5 6 7 (#2)1 4
#1判断:[3]大于[3]吗?不大,继续
[3] (#1)2 5 6 7 (#2)1 4
#1判断:2大于[3]吗?不大,继续
[3] 2 (#1)5 6 7 (#2)1 4
#1判断:5大于[3]吗?大,停,完成任务
两个侦察兵都找到完成自己的任务了,交换数字(人质)。
[3] 2 (#1)1 6 7 (#2)5 4
继续查找
[3] 2 (#1)1 6 (#2)7 5 4
#2判断:7小于[3]吗?不小,继续
[3] 2 (#1)1 (#2)6 7 5 4
#2判断:6小于[3]吗?不小,继续
[3] 2 (#1)(#2)1 6 7 5 4
#2判断:判……不用判了,两个侦察兵都遇上了
表示第一次移动结束,将相遇时的数与基准数交换
这里是1和[3]交换
1 2 (#1)(#2)[3] 6 7 5 4
如此[3]就是边界,在[3]左边的小于[3],在[3]右边的大于[3]
接着以[3]为边界切割数字
{1, 2} 3 {6, 5, 7, 4}
接着分别对{1, 2}和{6, 5, 7, 4}进行同样的操作,可递归
直到各个串被切割得只剩下一个数,此时排序已经结束
为什么选了最左边的数作为基准数,要右边优先开始搜索
假设我们以左端优先的
#1搜索,在5那里停住
[3] 2 (#1)5 6 7 1 (#2)4
#2搜索,在1那里停住
[3] 2 (#1)5 6 7 (#2)1 4
交换位置
[3] 2 (#1)1 6 7 (#2)5 4
#1搜索,在6那里停住
[3] 2 1 (#1)6 7 (#2)5 4
#2搜索,在1那里停住
[3] 2 (#2)1 (#1)6 7 5 4
发现了吗?这两货明晃晃的放着敌方朝自己大本营去了,像瞎了一样没法发现他们相遇了。
无法判断相遇时没办法将基准数归位,更无法切割字符串,这序我不排了。
代码实现
public class QuickSqrt {
static int[] nums = {3, 2, 5, 6, 7, 1, 4};
public static void main(String[] args) {
showArray();
System.out.println("排序前:");
quickSort(0, nums.length - 1);
System.out.println("排序后:");
showArray();
}
public static void quickSort(int startIndex, int endIndex) {
if (startIndex > endIndex) {
return;
}
//基准数
int baseNum = nums[startIndex];
//存储查找到的大于基准数的该数字在数组中的位置
int leftIndex = startIndex;
//存储查找到的小于基准数的该数字在数组中的位置
int rightIndex = endIndex;
while (leftIndex != rightIndex) {
//查找小于基准数的数的位置
while (nums[rightIndex] >= baseNum && rightIndex > leftIndex) {
rightIndex--;
}
//查找小于基准数的数的位置
while (nums[leftIndex] <= baseNum && leftIndex < rightIndex) {
leftIndex++;
}
//如果没有相遇,表示可以交换,否则已经移动完毕
if (leftIndex < rightIndex) {
int tempNum = nums[leftIndex];
nums[leftIndex] = nums[rightIndex];
nums[rightIndex] = tempNum;
}
}
//交换基准数与相遇位置的数
nums[startIndex] = nums[leftIndex];
nums[leftIndex] = baseNum;
//以基准数为界,左右切割,再次排序
quickSort(startIndex, leftIndex - 1);
quickSort(leftIndex + 1, endIndex);
}
public static void showArray() {
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i]);
if (i != nums.length - 1) {
System.out.print(", ");
}
}
System.out.println();
}
}
结果
排序前:
3, 2, 5, 6, 7, 1, 4
排序后:
1, 2, 3, 4, 5, 6, 7