思路
解决本题的思路主要是:每次快排可确定一个元素num在数组中的位置pos,以num为标准可将数组划分成左右两部分,下标小于pos的元素全部小于等于num,下标大于pos的元素全部大于等于num,根据第k大元素应处的位置挑选其中一个区间进行递归查找,直到num正好是我们要找的第k大元素。
代码实现
import java.util.*;
public class Main {
public static void main(String[] args) {
int[] arr = new int[10]; //生成随机数组
Random random = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(100);
}
int[] nums = new int[10]; //用来验证答案的数组
for (int i = 0; i < arr.length; i++) {
nums[i] = arr[i];
}
System.out.print("生成的原始数组为:");
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
int k = random.nextInt(10) + 1; //随机生成k值
int len = arr.length;
quickSort(arr, 0, len - 1, len - k); //排序结束后,第k大元素下标应该为len-k
Arrays.sort(nums);
System.out.print("排序得到的数组为: ");
for (int i = 0; i < arr.length; i++) {
System.out.print(nums[i] + " ");
}
System.out.println();
System.out.println("最大的第" + k + "个数预期的结果为: " + arr[len - k]);
System.out.println("最大的第" + k + "个数实际的结果为: " + nums[len - k]);
}
public static void quickSort(int[] arr,int l,int r,int target){
if(l<r){
int cur=partition(arr,l,r); //cur为本次排序中确定位置的元素下标
if(cur==target){ //若cur位置正好是len-k,则直接返回,否则只选取第k大元素存在的区间进行快排查找
return;
}else if(cur>=target){
quickSort(arr,l,cur-1,target);
}else{
quickSort(arr,cur+1,arr.length-1,target);
}
}
}
public static int partition(int[] arr,int l,int r){
int temp=arr[l]; //方法中确定的是arr[l]在数组中的位置,在其左边的元素都小于等于arr[l],在其右边的元素都大于等于arr[l]
while(l<r){
while(l<r&&arr[r]>=temp){
r--;
}
arr[l]=arr[r];
while(l<r&&arr[l]<=temp){
l++;
}
arr[r]=arr[l];
}
arr[l]=temp;
return l;
}
}
结果展示
性能分析
时间复杂度:O(N)
分析:最佳情况下,第一个被选中的元素恰好是第k大的元素,只需要调用partition方法一次,时间复杂度为O(n);最差情况下,需要不断递归查找,n+ 1/2 * n + 1/4 * n + 1/8 * n +…1/n * n <2n。综上时间复杂度为O(n)
空间复杂度:O(logN)
分析:由于用到了递归查询,所以需要O(logN)的栈空间