如果我们在算法中使用循环而不是递归,反之亦然,那么两者是否可以起到同样的作用?例如:检查给定的字符串是否为回文.我已经看到许多程序员使用递归作为一种手段来展示一个简单的迭代算法可以适应账单.编译器在决定使用什么方面起着至关重要的作用吗?
我面临一个问题,即递归和使用循环似乎都是自然的解决方案.对于像这样的案件,是否有惯例或"首选方法"?(显然它不像下面那么简单)
Item Search(string desired, Scope scope) {
foreach(Item item in scope.items)
if(item.name == desired)
return item;
return scope.Parent ? Search(desired, scope.Parent) : null;
}
Run Code Online (Sandbox Code Playgroud)
Item Search(string desired, Scope scope) {
for(Scope cur = scope; cur != null; cur = cur.Parent)
foreach(Item item in cur.items)
if(item.name == desired)
return item;
return null;
}
Run Code Online (Sandbox Code Playgroud) 什么是设计气味,递归的不良做法?一旦我看到resharper暗示改进,我就快速浏览了谷歌.看到关于将尾部递归重新分解为迭代并将其称为设计气味的众多评论.
public static void DebugOutput2(Exception ex) {
if (ex == null) {
return;
}
Debug.WriteLine(ex.Message);
if (ex.InnerException != null) {
DebugOutput2(ex.InnerException);
}
}
// WAS REFACTORED TO
public static void DebugOutput(Exception ex) {
if (ex == null) {
return;
}
while (true) {
Debug.WriteLine(ex.Message);
if (ex.InnerException != null) {
ex = ex.InnerException;
continue;
}
break;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:获得C#编译器处理评论.看起来它现在是递归的
Target .net 4.5.C#5.0
用于尾递归版本的ILDASM输出:显示递归调用而不是迭代
.method public hidebysig static void DebugOutput(class [mscorlib]System.Exception ex) cil managed
{
// Code size 54 (0x36)
.maxstack 2 …Run Code Online (Sandbox Code Playgroud) 好的,只是在F#中,这就是我现在理解的方式:
有些问题本质上是递归的(构建或读出树结构只能命名一个)然后你使用递归.在这些情况下,您最好使用尾递归来使堆栈中断
有些语言是纯粹的功能,所以你必须使用递归而不是while循环,即使问题不是递归的
所以我的问题是:既然F#也支持命令式范式,你会在F#中使用尾递归来解决那些不是自然递归的问题吗?特别是因为我已经读过编译器重新认识尾递归并且只是在while循环中转换它?
如果是这样:为什么?
我有这个方法来计算一些统计数据:
public void calculateAverage(int hour){
if (hour != 20) {
int data =0;
int times = 0;
for (CallQueue cq : queues) {
data += cq.getCallsByTime().get(hour);
times++;
}
averageData.add((double)data/times);
calculateAverage(hour + 1);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我非常自豪我创建了一个递归方法,但我知道这可以通过循环解决.
我的问题是:递归或循环解决这些问题会更好吗?
如果你有时间解释你的答案,请