关于跨应用程序的控制流,有an interesting post over here。
好吧,最近,我遇到了一个有趣的问题。在潜在(实际上)无限递归序列中生成第n个值。这个特定的算法将在其成功的深度处至少10-15个堆栈引用。我的第一个想法是抛出一个看起来像这样的成功事件(C#):
class SuccessException : Exception
{
public string Value
{ get; set; }
public SuccessException(string value)
: base()
{
Value = value;
}
}
然后做这样的事情:
try
{
Walk_r(tree);
}
catch (SuccessException ex)
{
result = ex.Value;
}
然后我的思绪在这里徘徊,在那里我一遍又一遍地听到,从来没有使用Exceptions进行流量控制。有没有借口?如果你要实现它,你将如何构建这样的结构?
答案 0 :(得分:5)
在这种情况下,我会查看你的Walk_r方法,你应该有一些返回值的东西,抛出一个异常来表示成功,这不是一种常见的做法,至少对任何看到的人来说都是非常困惑的代码。更不用说与例外相关的开销了。
答案 1 :(得分:1)
walk_r应该只是在命中时返回值。这是一个非常标准的递归示例。我看到的唯一潜在问题是你说它可能是无穷无尽的,必须通过保持递归深度的计数并停止在某个最大值来在walk_r代码中进行补偿。
异常实际上使编码非常奇怪,因为方法调用现在抛出异常来返回值,而不是简单地返回'normal'。
try
{
Walk_r(tree);
}
catch (SuccessException ex)
{
result = ex.Value;
}
成为
result = Walk_r(tree);
答案 2 :(得分:0)
将异常作为算法的一部分抛出并不是一个好主意,尤其是在.net中。在某些语言/平台中,异常在抛出时非常有效,而且当迭代可用时,异常通常是这样。
答案 3 :(得分:0)
为什么不直接返回结果值?如果它返回任何内容,则认为它是成功的。如果它无法返回值,则表示循环失败。
如果您必须从失败中退回,那么我建议您抛出异常。
答案 4 :(得分:0)
使用异常的问题是,tey(在宏观方案中)非常低效且速度慢。在递归函数中有一个if条件,只需要在需要时返回就可以了。老实说,现代PC上的内存量不大可能(虽然不是不可能),只有少量递归调用(<100)才能获得堆栈溢出。
如果堆栈是一个真正的问题,那么可能需要“创造性”并实现“深度限制搜索策略”,允许函数从递归返回并从最后(最深)节点重新开始搜索
总结:例外情况只应在特殊情况下使用,函数调用的成功我认为不符合资格。
答案 5 :(得分:0)
在我的书中使用正常程序流程中的异常是有史以来最糟糕的做法之一。 考虑正在寻找吞没异常的可怜的闷棍,并且正在运行调试器设置,以便在发生异常时停止。那个家伙现在变得疯了......他有一把斧头。 :P
答案 6 :(得分:0)
我将在这里扮演魔鬼的拥护者,并坚持说明成功的例外情况。抛出/捕获可能是昂贵的,但与搜索本身的成本相比,这可能是微不足道的,并且可能比早期退出该方法更少混淆。