問題
對(duì)一個(gè)已經(jīng)序列A[1,...,n],如何尋找其第k小的元素捌刮?
算法
使它在O(n)的時(shí)間復(fù)雜度內(nèi)解決
code
package wentao.algorithm.ex;
import java.util.Arrays;
public class FindTheLastKMinNum {
public static void main(String[] args) {
int[] A = { 8, 33, 17, 51, 57, 49, 35, 11, 25, 37, 14, 3, 2, 13, 52,
12, 6, 29, 32, 54, 5, 16, 22, 23, 7 };
int K = 18;
int theLastKMin = findTheLastKMinNum(A, 0, A.length - 1, K);
System.out.println("第" + K + "小的數(shù)是:" + theLastKMin);
}
/**
*
* 方法名: findTheLastKMinNum
* 方法作用: 分治法求第k小值
* 創(chuàng)建人:WENTAO Wan
* 創(chuàng)建時(shí)間:2016年4月4日 下午11:15:39
* @param @param A
* @param @param low
* @param @param high
* @param @param K
* @param @return
* 返回值類型: int
* @throws
*/
public static int findTheLastKMinNum(int[] A, int low, int high, int K) {
// 設(shè)置閾值
int p = high - low + 1;
if (p < 6) {
// 這里要注意新分配的空間 q+1造成干擾,不能直接Sort(A)
Arrays.sort(A, low, p);
return A[K - 1];
} else {
// 分為五段
int q = p / 5;
int remainder = p - q * 5;
// 每段排序并把中項(xiàng)存入mid
int[] mid = new int[q + 1];
for (int i = 0; i < q; i++) {
Arrays.sort(A, 5 * i, (i + 1) * 5);
mid[i] = A[i * 5 + 2]; // low
}
// 除不盡5之后的分為一段并找出中項(xiàng)存入mid
if (remainder > 0) {
Arrays.sort(A, 5 * q, 5 * q + remainder);
mid[q] = A[q * 5 + (remainder + 1) / 2 - 1];
}
// 中項(xiàng)集合的中項(xiàng)
int mm = findTheLastKMinNum(mid, 0, q - 1, (q + 1) / 2);
int[] A1 = new int[p];
int[] A2 = new int[p];
int[] A3 = new int[p];
int lenA1 = 0, lenA2 = 0, lenA3 = 0;
// 分別與中項(xiàng)比較舒岸,分為新的三段
for (int i = low; i <= high; i++) {
if (A[i] < mm) {
A1[lenA1++] = A[i];
} else if (A[i] == mm) {
A2[lenA2++] = A[i];
} else if (A[i] > mm) {
A3[lenA3++] = A[i];
}
}
// 將三段的長(zhǎng)度與K比較判斷K的位置并遞歸
int theLastKMin = 0;
if (lenA1 >= K) {
theLastKMin = findTheLastKMinNum(A1, 0, lenA1 - 1, K);
} else if (lenA2 + lenA1 < K) {
theLastKMin = findTheLastKMinNum(A3, 0, lenA3 - 1, K - lenA1
- lenA2);
} else if (lenA1 + lenA2 >= K) {
theLastKMin = mm;
}
return theLastKMin;
}
}
}