1. 基本思路
采用快速排序的方法, 不断在子序列中寻找符合条件的值, 不同于快排的是, 寻找第 k大的元素, 每次只需要对一边的数据进行排序即可.
2. 代码演示
public class SortDemo {
public static void main(String[] args) {
int[] arr = new int[] {1, 11, 2, 25, 36, 3, 14, 23, 6, 5, 9, 7, 10};
int k = 3;
System.out.println("第 " + k + "大的元素是: " + findMaxN(arr, k));
}
// 找出序列中第 k大的元素值
private static int findMaxN(int[] arr, int k) {
if (k > arr.length) {
throw new RuntimeException("k的值不可以大于序列长度");
}
return findMaxN(arr, 0, arr.length - 1, k);
}
// 寻找最k大的元素 主例程
private static int findMaxN(int[] arr, int left, int right, int k) {
// 三数中值法, 获取枢纽元 (基准值)
int pivot = median3(arr, left, right);
// 如果子序列长度为 1 or 2 or 3
// 则不需要走下列步骤, 因为此时子序列已经是有序的了 median3()方法中有排序
int size = right - left + 1;
if (size == 1 || size == 2 || size == 3) {
return arr[arr.length - k];
}
// 快速排序主例程
int i = left;
int j = right - 1;
for (; ; ) {
while (arr[++i] < pivot) {}
while (arr[--j] > pivot) {}
if (i < j) {
swap(arr, i, j);
} else {
break;
}
}
// 将枢纽元换回中间的位置
swap(arr, i, right - 1);
// 根据 k的范围, 决定对哪一部分(枢纽元左边还是右边)的元素进行再次交换
if (k <= i) {
findMaxN(arr, i + 1, right, k);
} else if (k > i + 1) {
findMaxN(arr, left, i - 1, k);
}
return arr[arr.length - k];
}
/**
* 三数中值分割法:
* 在序列首部, 末尾和中间三个元素中, 选择值处于中间的元素, 并返回其值
* 交换首部, 中间和尾部的值, 维持有序性.
*/
private static int median3(int[] arr, int left, int right) {
int size = right - left + 1;
if (size < 1) {
throw new RuntimeException("子序列长度至少为 1");
}
if (size == 1) {
return arr[left];
}
if (size == 2) {
if (arr[right] < arr[left]) {
swap(arr, left, right);
}
return arr[left];
}
int center = (right + left) / 2;
if (arr[center] < arr[left]) {
swap(arr, left, center);
}
if (arr[right] < arr[left]) {
swap(arr, left, right);
}
if (arr[right] < arr[center]) {
swap(arr, center, right);
}
// 将中值放到尾部之前的元素, 便于前面元素索引的移动
swap(arr, center, right - 1);
// 返回中值
return arr[right - 1];
}
// 交换数组中指定索引处的元素位置
private static void swap(int[] arr, int i, int j) {
if (i > arr.length - 1 || i < 0 || j > arr.length - 1 || j < 0) {
throw new RuntimeException("索引值有误");
}
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}