【问题标题】:Java divide and conquer algorithm stack overflow errorJava分治算法堆栈溢出错误
【发布时间】:2019-02-02 16:47:33
【问题描述】:

我正在尝试使用分治法找出 int 数组中最小数字的索引,但出现此堆栈溢出错误:

Exception in thread "main" java.lang.StackOverflowError
    at java.lang.StrictMath.floor(Unknown Source)
    at java.lang.Math.floor(Unknown Source)

这是我的分而治之方法:

private static int dC(int[] a, int f, int l) {
        if(f == 1)
            return f;
        if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
            return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
        else
            return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
    }

这是我在 main 方法中放入的内容:

int[] a = {35,30,40,50};

System.out.println(dC(a, 0, 3));

【问题讨论】:

  • 只需检查二进制搜索的源代码,并以此为基础编写您自己的代码。
  • 不相关的:使用有意义的名称。 a、f、l,它们都表示nothing。你写代码不是为了让编译器开心,你写代码是为了人类可以阅读和理解它。
  • 整数除法 (7 / 2 == 3) 没有 floor(double) 演员更适合。
  • (int)(Math.floor((double)(f+l)/2))(f+l)/2 相同(假设f+l 为非负数)。

标签: java arrays stack-overflow divide-and-conquer


【解决方案1】:

你的停止“规则”有问题

private static int dC(int[] a, int f, int l) {
        if(l == f) // <-- This mean you have one item, so you want to return it.
            return f;
        if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
            return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
        else
            return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
    }

另外,我会尝试只计算一次,所以像这样(也是 Joop Eggen 所说的整数算术):

private static int dC(int[] a, int f, int l) {
        if(l == f)
            return f;
        int m = (f+l) / 2;
        int left = dC(a, f, m);
        int right = dC(a, m+1, l);
        if(a[left] > a[right])
            return left;
        else
            return right;
    }

【讨论】:

  • 哦,是的,我发现我放的是 (f == 1) 而不是 (f == l)
【解决方案2】:

这只是经典的二分搜索问题。从我可以通过查看您的代码收集到的信息来看,您似乎陷入了用于对当前数组的左右子数组进行每次递归调用的逻辑中。我在下面使用的逻辑是将左递归从 start 到 (start+end)/2 的所有内容,以及从 ((start+end)/2) + 1 到 end 的所有内容进行右递归。这保证了永远不会有任何重叠。

当算法发现自己​​位于数组中的单个条目上时,就会发生基本情况。在这种情况下,我们只是返回该值,我们不会进一步递归。

private static int dC(int[] a, int start, int end) {
    if (start == end) return a[start];

    int left = dC(a, start, (start+end)/2);
    int right = dC(a, ((start+end)/2) + 1, end);

    return left < right ? left : right;
}

public static void main(String args[])
{
    int[] a = {10, 3, 74, 0, 99, 9, 13};
    System.out.println(dC(a, 0, 6));   // prints 0
}

Demo

注意:我不知道Math.floor 将在这里扮演什么角色,因为您使用的是 整数 数字数组,而不是双精度数或浮点数。我删除了它,因为我认为不需要它。

【讨论】:

    【解决方案3】:

    定位到min/max的索引是一个典型的问题,你可以试试:

    public static void main(String... args) {
        int[] arr = generateArrays(100, 1000, 0, 10000, true);
        int minIndex = findMinIndex(arr, 1, arr.length - 1);
        int theMin = arr[minIndex];
        Arrays.sort(arr);
        System.out.println(String.format("The min located correctly: %s", arr[0] == theMin));
    }
    
    private static int findMinIndex(int[] a, int l, int r) {
        if (r - l < 1) return l;
        int mid = l + (r - l) / 2;
        int lIndex = findMinIndex(a, l + 1, mid);
        int rIndex = findMinIndex(a, mid + 1, r);
        int theMinIndex = l;
        if (a[lIndex] < a[theMinIndex]) theMinIndex = lIndex;
        if (a[rIndex] < a[theMinIndex]) theMinIndex = rIndex;
        return theMinIndex;
    }
    

    以及生成随机数组的助手。

    public static int[] generateArrays(int minSize, int maxSize, int low, int high, boolean isUnique) {
        Random random = new Random(System.currentTimeMillis());
        int N = random.nextInt(maxSize - minSize + 1) + minSize;
        if (isUnique) {
            Set<Integer> intSet = new HashSet<>();
            while (intSet.size() < N) {
                intSet.add(random.nextInt(high - low) + low);
            }
            return intSet.stream().mapToInt(Integer::intValue).toArray();
        } else {
            int[] arr = new int[N];
            for (int i = 0; i < N; ++i) {
                arr[i] = random.nextInt(high - low) + low;
            }
            return arr;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-05
      • 2013-02-19
      • 2011-10-30
      • 1970-01-01
      相关资源
      最近更新 更多