作为一个家庭作业,我被分配编写算法,从无序的数字集中找到第k个有序数。作为一种方法,已经提出了算法median of medians
。
不幸的是,我的尝试失败了。如果有人发现错误 - 请纠正我。
private int find(int[] A, int size, int k) {
if (size <= 10) {
sort(A, 0, size);
return A[k];
} else {
int[] M = new int[size/5];
for (int i = 0; i < size / 5; i++) {
sort(A, i*5, (i+1) * 5);
M[i] = A[i*5 + 2];
}
int m = find(M, M.length, M.length / 2);
int[] aMinus = new int[size];
int aMinusIndex = 0;
int[] aEqual = new int[size];
int aEqualIndex = 0;
int[] aPlus = new int[size];
int aPlusIndex = 0;
for (int j = 0; j < size; j++) {
if (A[j] < m) {
aMinus[aMinusIndex++] = A[j];
} else if (A[j] == m) {
aEqual[aEqualIndex++] = A[j];
} else {
aPlus[aPlusIndex++] = A[j];
}
}
if (aMinusIndex <= k) {
return find(aMinus, aMinusIndex, k);
} else if (aMinusIndex + aEqualIndex <= k) {
return m;
} else {
return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex);
}
}
}
private void sort(int[] t, int begin, int end) { //simple insertion sort
for (int i = begin; i < end; i++) {
int j = i;
int element = t[i];
while ((j > begin) && (t[j - 1] > element)) {
t[j] = t[j - 1];
j--;
}
t[j] = element;
}
}
我正在运行的测试是输入数字{200,199,198,...,1)并从有序数组中获取第一个数字。我得到了:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -13
由于递归调用而在return A[k]
行抛出的内容:
return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex);
答案 0 :(得分:2)
递归步骤的分支逻辑是向后的。你试图找到第k个最小的数字,你发现有一个小于m的mininIndex数字,aEqualIndex等于m,aPlusIndex大于m。
你应该在aMinus中搜索aMinusIndex&gt; = k,而不是aMinusIndex&lt; = k - 等等。
(通过查看极端情况很容易看到:说小数字小于m。然后显然你不应该在空数组中搜索任何东西,但是因为0 <= k,你将是。)
答案 1 :(得分:0)
我不确切地知道你的问题是什么,但你肯定应该不这样做:
sort(A, i*5, (i+1) * 5);
此外,你不应该做那么多的复制,当你这样做时,你没有获得任何表现。该算法应该在适当的位置完成。
查看此维基百科:Selection algorithm
答案 2 :(得分:0)
我知道这是家庭作业,所以你的选择可能受到限制,但我不知道中位数中位数在这里是多么有用。只需使用标准算法对整个数组进行排序,然后选择第k个元素。中位数的中位数有助于找到一个非常好的支点。对于200长度的数据,您不会节省太多时间。
据我所知,你不能准确获得中位数,百分位数或第k个元素,而不是最终排序整个输入数组。使用子集会产生估计值。如果这是错的,我真的很想知道,因为我最近在编写代码来查找数百万个数组中的百分位数!
P.S。可能是因为我不完全理解你的代码...