java如何将递归转换为迭代?
这个问题被问了几次,但我仍然发现很难将易读且直观的代码转换为迭代代码。例如,我在练习一个编码问题,我得到了26个整数,表示每个字符在字符串中出现的次数。我应该打印所有可能的字符串。下面是我的递归代码
private static void combinatorial(String prefix, ArrayList<Integer> remainingToFill,
int totalLength) {
if (prefix.length() == totalLength) {
System.out.println(prefix);
}
for (int i = 0; i < remainingToFill.size(); i++) {
if (remainingToFill.get(i) > 0) {
ArrayList<Integer> toFill = new ArrayList<>(remainingToFill);
toFill.set(i, toFill.get(i) - 1);
combinatorial(prefix + (char) ('a' + i), toFill, totalLength);
}
}
}
我编写了这个迭代版本,但生成的函数要复杂得多,不可读,而且我花了更多的时间来编写它。我如何解决这类问题?有没有什么简单的技术可以让我遵循,从而产生简单易读的代码
# 1 楼答案
编程语言支持程序的递归表达式的原因是它通常比显式迭代形式简单。所以你的问题几乎是自我回答
然而,确实有一种方法可以将递归形式转换为总是有效的迭代形式。有一种带有
goto
的语言是有帮助的,而Java没有首先,让我们清理java。我们希望使用最少数量的参数和局部变量,因为剩下的必须放在显式堆栈上。我们开始吧。除了
i
和prefix
之外,我们什么都不用了现在让我们转录到C,它有
goto
。在这里,通过添加一个全局字符串缓冲区,很容易消除甚至prefix
现在,规则是:
i
,所以我们甚至不需要记录。一堆int
就可以了李>push
放在堆栈上,然后rtn:
李>rtn:
李>这些规则基本上模仿编译器将生成的代码来处理递归调用
综上所述,我们有:
如果您仔细遵循这些步骤,您的代码将首先运行,然后每次尝试。唯一的额外提示是,当存在多个递归调用站点时,您需要为每个
rtn1:
、rtn2:
等添加一个返回标签,并在堆栈中添加一个表示返回站点的int
字段,在epilog中使用switch语句跳转到正确的返回站点当然这不是很好的代码。我们想去掉
goto
。通过做“代数”将gotos
转换成循环,这总是可能的。有几十种转换技术。。。太多了,这里无法描述。这很像在数学课上简化方程式。有时需要添加布尔标志。不过,在这种情况下,我们不需要这样做。我完成了这个:为了好玩,回到Java:
# 2 楼答案