除了典型的以外,还有哪些其他语言独立的设计递归函数的方法:
if (counter < 1)
return output;
else
callSelf();
是否存在其他方法?每当查看示例时,我总会看到上面代码的版本。
谢谢! :)
答案 0 :(得分:6)
这就是它。
递归函数设计几乎就像“我可以返回一个值还是需要进一步处理?”一样简单。并且“Processing返回了一个值,在我传递之前我该怎么办?”
尾递归只是编译器/解释器可用于提高性能的优化方法。本质上,如果递归函数遵循严格格式(在递归调用之后没有任何反应,通常意味着递归调用总是与return
配对),则可以优化递归函数并将其重写为for循环。
答案 1 :(得分:5)
你的问题究竟是什么? 只是尝试一些答案; - )
有许多类型的递归:
“标准”递归
let rec sum = function
| [] -> 0
| x::x' -> x + sum x'
尾递归
let rec sum acc = function
| [] -> acc
| x::x' -> sum (x + acc) x'
相互递归
let rec f() = g()
and g() = f()
let factorial n = fix(fun rec n -> if n < 1 then 1 else n * rec (n - 1)) n
递归的应用程序列表非常丰富。在函数式编程中,任何迭代代码(for-loops等)都通过递归来表达!
另一个好例子:
let rec sumTree = function
| End -> 0
| Node(val, right, left) = val + sumTree right + sumTree left
递归的主要“最佳实践”是确保在某个时刻满足您的终止条件,因此您通常会使用比初始调用中更小的数据自我调用函数(只需一部分)的树)。其他一切都会导致无休止的递归。
答案 2 :(得分:3)
嗯,您需要一些方法知道何时停止递归。这就是你的counter < 1
,对吗?我经常删除/添加项目到列表,遍历树,并在递归时执行数学函数。最终,您需要知道何时停止递归以及何时不停止递归,因此我没有看到任何其他无法归结为counter < 1
的选项。
function ProcessNode(node)
//Do stuff
while (node.Next != null)
ProcessNode(node.Next);
function ManipulateList(list)
//Do stuff, adding and removing items based on logic
if (testCondition)
return;
else
ManipulateList(list);
答案 3 :(得分:1)
Google在recursion上提供了大量信息。 :)
答案 4 :(得分:1)
有很多变化,例如:
foreach (child in parameter.GetChildren()) {
callself(child)
}
或
switch (param.length) {
case 1: return param[0];
case 2: return param[0] + param[1];
default: return callself(param.FirstHalf()) + callself(param.LastHalf());
}
他们所有人的共同点是,他们将任务分配给较小的任务,然后用自己来解决较小的任务,直到它们太小而无法通过简单的操作来解决。
答案 5 :(得分:1)
在惰性编程语言中,您可以进行不定义端点的递归。结果可能是无限的数据结构,但只要你不尝试使用它,那就没关系。例如,在Haskell中定义整个斐波纳契系列的常用方法是:
fibS = 1:1: zipWith (+) fibS (tail fibS)
这转化为以下英语:斐波纳契数列为1,后跟1,其后是系列,它是斐波那契数列和没有第一个元素的斐波纳契数列的元素和。
这听起来像递归定义,而不是递归函数调用,但在Haskell中没有很大的区别 - 上面只是一个'nullary函数'(一个不带参数的函数)。
通常使用它,你只需要使用fibS的前N个元素。事实上你可以使用所有这些(例如打印全部),只要你对你的程序永远运行感到满意: - )
对于使用“全部”无限递归的更有用的示例,Web服务器可能具有使用不终止的递归函数永久定义的“主循环”。
编辑:如果存在“懒惰”的某些元素,这些原则当然可以应用于其他语言。以下是使用生成器移植到Python的fibS的上述实现:
def zipWith(func, iter1, iter2):
while True:
yield func(iter1.next(), iter2.next())
def tail(iter):
iter.next()
for x in iter:
yield x
def fibS():
yield 1
yield 1
for x in zipWith(lambda x,y: x + y, fibS(), tail(fibS())):
yield x
# Test it by printing out the first n elements.
def take(n, iter):
while n > 0:
yield iter.next()
n = n - 1
print list(take(10, fibS()))
不要指望它与Haskell版本一样高效!您可以使用某种黑客和某种全局对象来提高效率。但请注意缺乏明确的终止条件。
答案 6 :(得分:0)
如果您想要停止递归,则必须进行测试。
但是你可以拥有一些变化的东西,比如河内塔算法(2个递归调用):
int Hanoi( source, mid, destination, height ) {
if ( height == 1 ) { print source '->' destination }
else
Hanoi ( source, destination, mid, height - 1 ) ; # move all upper tower from source to mid
print source '->' destination;
Hanoi ( mid , source, destination, height -1 ) ; # move all the upper tower from mid to destination
}
Hanoi ( "0", "1", "2", 8 );
将打印将8张光盘从源移动到dest的解决方案。有关游戏规则,请参阅http://en.wikipedia.org/wiki/Tower_of_Hanoi。
答案 7 :(得分:0)
“最佳实践”是尝试使用结构感应(粗略地说,是数据结构的折叠)。如果失败,您可能需要考虑一般(不受限制的)递归。
例如,在处理列表时,通常使用折叠。许多函数,例如连接和追加都很容易以这种方式描述。