快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
关键部分:
- 被某个数,分割为两部分,其中一部分比分割数小,另外一部分比分割数大
- 不断的进行分割,满足上面的性质,直到不可再分为止
解
根据上面的思想,画了图:
- 每次都随机找一个数
- 然后按照被找到的数进行分割
编码
- 随机找一个数
int randomIndex = new Random().nextInt(end - start) + start;
int splitNumber = nums[randomIndex];
System.out.println(
String.format("当前start:%d, end:%d,选取的Index为:%d , 数字为:%d" ,start,end, randomIndex,splitNumber)
);
复制代码
- 根据分割数进行排序
int gt = end;
int lt = start;
// 新开辟一个数组区间
int[] tmp = new int[nums.length];
for (int i = start; i <= end; i++) {
// 比分割数大的都放在数组后面
if (nums[i] > splitNumber){
tmp[gt] = nums[i];
gt--;
// 比分割数小的都放在数组前面
}else if (nums[i] < splitNumber){
tmp[lt] = nums[i];
lt++;
}
}
// 在分割数的位置给分割数赋值
for (int i = lt; i <= gt; i++) {
tmp[i] = splitNumber;
}
复制代码
- 将数字赋值到原本的数组
for (int i = start; i <= end; i++) {
nums[i] = tmp[i];
}
复制代码
- 对剩下的两部分,再次分割
// 分割左面的
quickSort(nums,start,lt-1);
// 分割右面的
quickSort(nums,gt+1,end);
复制代码
- 完整代码
static void quickSort(int[] nums){
quickSort(nums,0,nums.length - 1);
}
private static void quickSort(int[] nums, int start, int end) {
if (end <= start
){
return;
}
int gt = end;
int lt = start;
int randomIndex = new Random().nextInt(end - start) + start;
int splitNumber = nums[randomIndex];
System.out.println(
String.format("当前start:%d, end:%d,选取的Index为:%d , 数字为:%d" ,start,end, randomIndex,splitNumber));
int[] tmp = new int[nums.length];
for (int i = start; i <= end; i++) {
if (nums[i] > splitNumber){
tmp[gt] = nums[i];
gt--;
}else if (nums[i] < splitNumber){
tmp[lt] = nums[i];
lt++;
}
}
for (int i = lt; i <= gt; i++) {
tmp[i] = splitNumber;
}
System.out.println("临时数组:" + Arrays.toString(tmp));
System.out.print(
String.format("lt=%d,gt=%d,currentArr: ",lt,gt)
);
for (int i = start; i <= end; i++) {
nums[i] = tmp[i];
System.out.print(tmp[i]);
System.out.print(",");
}
System.out.println("");
quickSort(nums,start,lt-1);
quickSort(nums,gt+1,end);
}
复制代码
测试结果
额外
感觉上面的方式有点浪费空间,在分割数组的时候,如果不开辟新的数组应该也是可以的。尝试不分割数组的话
需要考虑:
- 当前要比较的下标index,以及下标对应的元素currentNum
- 存放大于index元素的下标gt , 存放小于index元素的下标lt
编码:
- 下标index,统一取为当前数组的第一个元素
int randomIndex = start;
int splitNumber = nums[randomIndex];
复制代码
- 进行数组处理,拆分为两部分
int gt = end;
int lt = start;
for (int i = start; i <= end; i++) {
// 以及处理完了
if (gt == i){
nums[lt] = splitNumber;
break;
}
// 大的放gt那边,交换元素之后,记得不要让i的下标继续走
if (nums[i] > splitNumber){
Helper.swap(nums,i,gt);
gt--;
i--;
// 小的放lt
}else if (nums[i] < splitNumber){
nums[lt] = nums[i];
lt++;
}
}
复制代码
- 重复上面的步骤
quickSortNew(nums,start,lt);
quickSortNew(nums,gt,end);
复制代码
- 完整代码
private static void quickSortNew(int[] nums, int start, int end) {
if (end <= start
){
return;
}
int gt = end;
int lt = start;
// int randomIndex = new Random().nextInt(end - start) + start;
int randomIndex = start;
int splitNumber = nums[randomIndex];
System.out.println(
String.format("当前start:%d, end:%d,选取的Index为:%d , 数字为:%d" ,start,end, randomIndex,splitNumber));
for (int i = start; i <= end; i++) {
if (gt == i){
nums[lt] = splitNumber;
break;
}
if (nums[i] > splitNumber){
Helper.swap(nums,i,gt);
gt--;
i--;
}else if (nums[i] < splitNumber){
nums[lt] = nums[i];
lt++;
}
}
System.out.println(
String.format("lt=%d,gt=%d,currentArr:=%s ",lt,gt,Arrays.toString(nums))
);
quickSortNew(nums,start,lt);
quickSortNew(nums,gt,end);
}
复制代码
- 测试效果
最后
里面的打印信息为了调试,在地柜的时候,debug的方式感觉不如打印的方式直白,通过查看打印信息,一眼就看出来程序走到了哪一个步骤。
关于快速排序就到这了。