同样还是先上代码:
import java.util.Arrays;
import java.util.Random;
public class A010_数组中第K小的元素 {
public static void main(String[] args) {
int len = 10;
int max = 20;
int k = 3;
int[] arr = getRandomArr(len, max);
System.out.println(Arrays.toString(arr));
int idxValue = selectK(arr, 0, len - 1, k);
System.out.println(idxValue);
}
public static int selectK(int[] arr, int l, int r, int k) {
int idx = partion(arr, l, r);
int qk = idx - l + 1;// 为什么要-L+1
if (qk == k)
return arr[idx];
else if (qk > k)
return selectK(arr, l, idx - 1, k);
else
return selectK(arr, idx + 1, r, k - qk);
}
public static int partion(int[] arr, int left, int right) {
int mid = (left + right) / 2;
int midValue = -1;
if (arr[left] <= arr[mid] && arr[left] >= arr[right]) {
midValue = left;
} else if (arr[right] <= arr[mid] && arr[right] >= arr[left]) {
midValue = right;
} else
midValue = mid;
int t = arr[midValue];
arr[midValue] = arr[left];
arr[left] = t;
int head = arr[left];
int L = left;
int R = right;
while (L < R) {
while (L < R && head < arr[R])
R--;
while (L < R && head >= arr[L])
L++;
t = arr[L];
arr[L] = arr[R];
arr[R] = t;
}
arr[left] = arr[R];
arr[R] = head;
return R;
}
public static int[] getRandomArr(int len, int max) {
int[] arr = new int[len];
Random ran = new Random();
for (int i = 0; i < len; i++) {
arr[i] = ran.nextInt(max) + 1;
}
return arr;
}
}
还是同样的套路生成随机数组,随后调用selectK函数,这个函数的作用是直接返回那个我们要找的第k小的数;
进入selectK函数后首先调用的是partion函数,该方法的作用与三点中值法的快排作用类似,差别就是,我在之前快排的时候返回值是void,这里是返回下标idx,idx返回的就是排序后,主元的那个值得下标也就是说,现在的idx,左边都是小于它的,右边都是大于它的,而qk就是第几个元素,如果qk比要求的k大,那就去idx的左边找,如果qk比要求的k的值小,那么就要去idx的右边找,然后这里需要注意的是,k是要减去qk的,因为求的是第k个元素,在右边的话,长度肯定是比整体长度要小的,所以新的k的值也要整体缩小,所以需要传入k-qk的长度,比如要求的是第五个小的,然后这个数组中一共有6个元素,那么第一次partion函数走下来后,idx是在左边的,那么这个时候,就要去右边去找,那么这个时候的第“零”个元素,其实就是idx+1了,那么从这个开始第第k的元素,就是k-qk了。