【问题标题】:Java Recursion over 2 parameters and in two directionsJava递归超过2个参数和两个方向
【发布时间】:2013-08-05 13:21:50
【问题描述】:

我希望以通用方式同时递归两个参数。这里有一些解释:

这就是函数调用的样子Func(int a, int b)

  • 呼叫 0:Func(0, 0)
  • 呼叫 1:Func(0, 1)
  • 呼叫 1:Func(1, 0)
  • 呼叫 1:Func(0, -1)
  • 呼叫 1:Func(-1, 0)

我将如何在代码中实现这一点,确保以下语句:

  • 考虑了a INRANGE (-INF, INF)b INRANGE (-INF, INF) 的所有可能组合。
  • 没有开销,我的意思是在递归中不会多次使用相同的函数。

我稍后想扩展它以对 7 个参数执行相同的操作。

问候。

【问题讨论】:

  • ps。这是stackoverflow.com/questions/18058711/… 的后续,我的目标是这篇文章更简洁。也许旧帖子应该关闭?
  • 如果旧问题对任何人都没有未来价值并且没有被赞成的答案,它可以而且应该被删除(你应该能够自己删除它)。
  • 解决方案越通用,速度就越慢。性能是一个考虑因素。顺便说一句:对 7 个参数进行 10 个值的通用搜索将比 2 个参数花费 100,000 倍的时间。对于 1000 个值,这将花费 10 亿倍的时间,并且可能不再实用。
  • @Dukeling 这样的问题删除有些争议,因为它们可能会导致大量问题被禁止。
  • 您可以在 X,Y 网格上螺旋从 (0, 0) 开始,但这不需要递归完成。

标签: java recursion


【解决方案1】:

这是我对螺旋式方法的看法:

// this is your function
static void func(int x, int y)
{
  System.out.println("x = "+x+", y = "+y);
}

// this calls func for all possible combinations of signs of the variables in arr
static void allPossibleSigns(int pos, Integer... arr)
{
  if (pos == arr.length)
  {
     func(arr[0], arr[1]); // not really generic
  }
  else
  {
     allPossibleSigns(pos+1, arr);
     arr[pos] = -arr[pos];
     if (arr[pos] != 0)
        allPossibleSigns(pos+1, arr);
  }
}

static void caller()
{
  for (int t = 0; t < MAX; t++)
  for (int x = 0; x <= t; x++)
  {
     int y = (t-x);
     allPossibleSigns(0, x, y);
  }
}

如果您想要比func(arr[0], arr[1]); 更通用的东西,可以将其替换为:

Method[] methods = NewMain.class.getMethods();
for (Method m: methods)
{
   if (m.getName().equals("func"))
      m.invoke(null, arr);
}

并添加一些错误检查。由于这种方法,我在printAllPossibleSigns 中使用了Integer... 而不是int...(以上不适用于int...)。这假设您只有一个名为func 的函数。如果不是这种情况,您将不得不添加一些额外的检查。

对于MAX = 4,它会打印:

x = 0, y = 0
x = 0, y = 1
x = 0, y = -1
x = 1, y = 0
x = -1, y = 0
x = 0, y = 2
x = 0, y = -2
x = 1, y = 1
x = 1, y = -1
x = -1, y = -1
x = -1, y = 1
x = 2, y = 0
x = -2, y = 0
x = 0, y = 3
x = 0, y = -3
x = 1, y = 2
x = 1, y = -2
x = -1, y = -2
x = -1, y = 2
x = 2, y = 1
x = 2, y = -1
x = -2, y = -1
x = -2, y = 1
x = 3, y = 0
x = -3, y = 0

这将如何扩展到 3 个变量可能并不完全清楚,所以这里是 caller 3 个变量:

static void caller()
{
  for (int t = 0; t < MAX; t++)
  for (int x = 0; x <= t; x++)
  for (int y = 0; y <= (t-x); y++)
  {
     int z = (t-x-y);
     printAllPossibleSigns(0, x, y, z);
  }
}

这就是你必须更改的所有内容,当然还有你的功能,如果你没有选择通用方法,func(arr[0], arr[1]);

【讨论】:

  • 我有点理解,只是if (pos == arr.length) 对我来说有点像魔术。
  • 这是我们递归函数的最深一步,当我们到达数组的末尾时。因此,该函数生成从数组开头到结尾的所有符号组合。最后,我们应该简单地调用该函数。我希望这能澄清一点,我想我不能更好地解释它。
【解决方案2】:

我提出了一个螺旋式的、非递归的最简单的方法。 为了便于阅读,每一步都会再次选择移动。

int x = 0;
int y = 0;
for (int t = 0; t < 100; ++t) {
    func(x, y);
    if (x <= 0 && y == 0) { // Widen spiral.
        --x;
        ++y; // So next condition takes next.
    } else if (x < 0 && y >= 0) { // Left, upper quadrant.
        ++x;
        ++y;
    } else if (x >= 0 && y > 0) { // Right, upper.
        ++x;
        --y;
    } else if (x >= 0 && y <= 0) { // Right, lower.
        --x;
        --y;
    } else if (x < 0 && y < 0) { // Left, lower.
        --x;
        ++y;
    } else {
        throw new IllegalStateException("x = " + x + ", y = " + y);
    }
}

我没有尝试代码!检查条件。

【讨论】:

  • 我正在努力解决如何将其用于nD。 3D 将难以理解,而 7D 则永远不可能。尽管对于我的应用程序而言,最佳解决方案非常需要 7 维螺旋。
【解决方案3】:

也许组合学的一些知识会有所帮助。对我来说,这看起来像你有一组从 -N 到 +N 的元素。现在您想为长度 == 7 的每个 variation 元素调用一个函数。

这样的范围可能真的很大。根据您要调用的操作成本,这可能需要比您的寿命更长的时间。

我会写一个Iterator,它会在每次调用 next() 时提供元素的新变体(这是您的函数参数)。

如果您需要大数字,您可以BigInteger 实现这样的迭代器。您可以使用ArrayList 并在每次迭代时更改它的元素。如果您搜索组合算法或排列/变化算法,您可能会找到详细信息,甚至可能是实现。

另一种(类似)方式(我认为开销更大)是仅使用一个数字(例如 BigInteger)来标记当前变化。在每次迭代中,您将此变体索引号加 1。

要从此数字中获取参数,您必须对此变体索引执行基本转换。基数将是元素集中的元素数量。结果数字的每个数字的范围为 0 到元素的数量 -1。从此,您可以使用每个数字从元素列表中获取函数调用的参数。

我比前一段时间做了,而且效果很好。不能保证我能找到它。

【讨论】:

    【解决方案4】:

    对于 n 维:

    下面我使用正数作为坐标。对于解决方案中的每个正(大于 0)坐标,使坐标为负也是一个解决方案(几乎是 2^n 个解决方案的因子)。 (使用正数可以简化解的解读。)

    这是n维坐标向量的解。选择坐标时,“半径”=坐标总和。

    static void func(int[] x) {
        System.out.printf("%s%n", Arrays.toString(x));
    }
    
    /**
     * Call many funcs with several coordinates.
     * @param x n-dimensional coordinates.
     * @param fromI starting index for variable coordinates.
     * @param r radius, equal to the sum of x[>= fromIndex].
     * @param t downward counter limiting the number of calls.
     * @return new value of t.
     */
    static int callFuncsForRadius(int[] x, int fromIndex, int r, int t) {
        if (t <= 0) {
            return t;
        }
        if (fromIndex >= x.length) { // Nothing more to vary.
            if (r == 0) { // Read radius sum.
                func(x);
                --t;
            }
            return t;
        }
        for (int rNext = r; rNext >= 0; --rNext) {
            x[fromIndex] = rNext;
            t = callFuncsForRadius(x, fromIndex + 1, r - rNext, t);
            if (t <= 0) {
                break;
            }
        }
        return t;
    }
    
    static int callFuncs(int[] x, int t) {
        int r = 0;
        while (t > 0) {
            t = callFuncsForRadius(x, 0, r, t);
            ++r;
        }
        return t;
    }
    
    public static void main(String[] args) {
        int n = 3;
        int[] x = new int[n];
        int t = 10; // N^n, where N = 2^31.
        callFuncs(x, t);
    }
    

    【讨论】:

      猜你喜欢
      • 2011-09-13
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多