手撕快排完整代码
import java.util.Scanner;
public class Main {
public static void quickSort(int nums[],int l,int r){
if(l>=r) return;
int i = l-1,j = r+1;
//下标中值作为基准值
int x = nums[l+r>>1];
//排序:基准左边的值都小于基准值,基准右边的值都大于基准值
while(i<j){
while(nums[++i]<x);//在左边寻找第一个大于等于基准的值,可能会找到基准右边
while(nums[--j]>x);//在右边寻找第一个小于等于基准的值,可能会找到基准左边
//找值时可能越过基准值,所以要判断
if(i<j){
int tem = nums[i];
nums[i] = nums[j];
nums[j] = tem;
}
}
//边界见注解
quickSort(nums,l,j);
quickSort(nums,j+1,r);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int nums[] = new int[n];
for(int i = 0;i<n;i++){
nums[i] = in.nextInt();
}
quickSort(nums,0,nums.length-1);
for(int i=0;i<nums.length;i++){
System.out.print(nums[i]+" ");
}
}
}
习惯用 C++写题之后换成 Java 是真难受,输入输出都很麻烦 写个完整代码以后参考
关于两个while
循环:
在代码中,i
和 j
是用来寻找两个元素并交换它们的指针。i
逐步向右移动,找到一个大于或等于基准值 x
的元素;j
逐步向左移动,找到一个小于或等于基准值 x
的元素。
当 i
和 j
相遇时,表示左边和右边的所有元素已经按基准值 x
排好了序。所以,交换发生后,nums[i]
或 nums[j]
位置是正确的。
然后,递归调用 quickSort(nums, l, j)
和 quickSort(nums, j + 1, r)
来处理左边和右边的子数组。
关于边界:
为什么是 j
而不是 i
作为边界?
i
是用于从左边寻找比基准大的元素,它可能会跨越基准的正确位置,而 j
总是会停在一个有效的位置(即最后一个小于基准值的元素的位置)。
在排序完成后,j
的位置是基准值应该放置的位置,因为 j
是最后一个小于等于基准值的元素的索引。
i
和 j
可能会交错,而递归时需要将基准元素的左右两部分分别处理。所以基准的右侧部分从 j + 1
开始处理,而左侧部分到 j
。