代码行return tournamentTreeKSelection(listToArray(list), k);
导致程序无限递归,我无法找到确切的原因。
import java.util.ArrayList;
import java.util.Arrays;
public class TournamentTree {
public static int tournamentTreeKSelection(int[] data, int k) {
ArrayList<Integer> list = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>(list);
for(int i = 0; i < data.length - 1; i += 2) {
list.add(max(data[i] , data[i + 1]));
}
if(list.size() % 2 != 0) list.add(-1);
if(k > 1 && list.size() == 1) {
for(int i = 0; i < list2.size(); i++)
if(list2.get(i) == list.get(0))
list2.remove(i);
return tournamentTreeKSelection(listToArray(list2),--k);
}
if(list.size() == 1) return list.get(0);
return tournamentTreeKSelection(listToArray(list), k);
}
public static int max(int a, int b) {
return a > b ? a : b;
}
public static int[] listToArray(ArrayList<Integer> arr) {
int[] arr2 = new int[arr.size()];
for(int i = 0; i < arr.size(); i++)
arr2[i] = arr.get(i);
return arr2;
}
}
我使用数组[10,9,8,7,6,5,4,3,2,1]进行了手动跟踪,我能够归结为单个元素[10],为什么然后呢?是程序的运行导致堆栈溢出?
答案 0 :(得分:4)
考虑到或多或少相同的算法,我将如何做到这一点:
喜欢那个
public static int tournamentTreeKSelection(int[] data, int k) {
int max = -1;
for (int i : data) {
max = Math.max(max, i);
}
if (k == 1) {
return max;
}
List<Integer> results = new ArrayList<>();
for (int i : data) {
if (i != max) {
results.add(i);
}
}
return tournamentTreeKSelection(listToArray(results), k - 1);
}
您选择项目一半的部分对我没有意义,因为您丢失了其他元素相对位置的信息。 (所以我把它删除了。)
答案 1 :(得分:1)
答案 2 :(得分:1)
njzk2的答案确实比你想要做的更简单,因为它消除了锦标赛树的概念。
如果您需要使用锦标赛实施,我会给您一些关于您的代码不起作用的指示。
使用锦标赛方法找到最大数量后,您应该将其从原始列表中删除,然后再次调用该方法以获取剩余n-1个数字和k-1的数组,因为您的任务现在要查找k-1
个剩余数字的最高数量。
您尝试使用list2
执行此操作,但未正确初始化list2
。您将其初始化为空。您必须跟踪原始数组,以便每次找到剩余数组的max元素时可以从中删除max元素。为此,您应该为方法添加另一个数组参数。最初它将包含原始数组,每次找到最大数字时,它将包含通过删除最大数字得到的数组。
也许您可以通过使用两个递归方法来简化实现,一种方法用于使用旅游树查找最大数量,另一种方法将使用第一种方法来查找第k个最高数字。
这是有道理的,因为你有两个不同的递归步骤不能很好地协同工作 - 一个将数组减半,直到你到达一个元素,而另一个从数组中删除一个元素并减少k,直到k达到1。
public static int getKthElement (int[] data, int k)
{
int max = findMaxByTournament (data);
if (k == 1) {
return max;
} else {
// create an array containing the lowest data.length-1
// elements of the data array
int[] data2 = new int[data.length-1];
boolean foundMax = false;
int count = 0;
for (int n : data) {
if (n < max || foundMax) {
data2[count++] = n;
}
if (n == max) {
foundMax = true; // this flag is required in case more than
// one element has the maximum value
}
}
return getKthElement (data2, k - 1);
}
}
public static int findMaxByTournament (int[] data)
{
// here you do something similar to what you already did - find the
// max number of each pair and call this method recursively with half
// the elements until you have one remaining element
}
答案 3 :(得分:0)
我在代码中添加了注释(我发现了很多递归问题):
public static int tournamentTreeKSelection(int[] data, int k) {
ArrayList<Integer> list = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>(list);
for(int i = 0; i < data.length - 1; i += 2) {
list.add(max(data[i] , data[i + 1]));
}
if(list.size() % 2 != 0) list.add(-1);
if(k > 1 && list.size() == 1) { // if list.size() % 2 != 0, we never go to this,
// because we never decrease list.count and never decrease k before this block
for(int i = 0; i < list2.size(); i++)
if(list2.get(i) == list.get(0))
list2.remove(i);
return tournamentTreeKSelection(listToArray(list2),--k);
}
// if we add two element or more in list, we never stop after that
if(list.size() == 1) return list.get(0);
// we never decrease k, so call tournamentTreeKSelection with same parameters -> it's run forever
return tournamentTreeKSelection(listToArray(list), k);
}
// main problem that listToArray returns copy of list, but you run tournamentTreeKSelection(listToArray(list), k) with same parameters, if you listToArray returns int[] less that list, tournamentTreeKSelection can stop
public static int[] listToArray(ArrayList<Integer> arr) {
...