我对实现递归方法的两种不同方法的优点有疑问。我一直遵循版本1的方法,即接受单个Node参数,但我最近遇到了版本2中使用的样式,它接受一组节点。
考虑以下Node类以及Visit方法的2个版本:
class Node
{
public List<Node> children = new List<Node>();
// other data members
}
版本1接受单个Node参数:
Visit(Node n)
{
DoSomethingUsefulWith(n);
foreach (Node child in n.children)
Visit(child);
}
版本2接受节点集合:
Visit(List<Node> nodes)
{
foreach (Node n in nodes)
{
DoSomethingUsefulWith(n);
Visit(n.children);
}
}
使用一种形式而不是另一种形式,是否有任何好处,甚至是风格上的?选择是否应该完全取决于您是从单个节点开始还是从节点集合开始,即使在任何一种情况下都使用任一方法版本都是微不足道的?
答案 0 :(得分:2)
我不会实现版本2,始终版本为1 版本2基本上是for-each循环中的版本1
如果您稍后决定要使用一个参数调用该方法,则可以始终重新使用版本1 如果您只有版本2和一个节点,则必须创建一个虚拟列表以使用版本1.
我不认为这里的表现是一个真正的问题。两种方法都有一个(通过引用)参数,它们应该使用大约相同数量的内存。
然而,.NET可能能够更好地优化两者之一。简要介绍两种方法。
答案 1 :(得分:2)
我更喜欢采用单个节点的签名,因为如果我只想在该节点上执行操作并且它是子节点,那么我就不必构造一个人工列表。它在节点列表上同样易于使用,您只需遍历列表并将其应用于每个节点。
答案 2 :(得分:1)
您应该在递归函数中传递尽可能少的参数(即使是专用于您使用的类型的内存大小)。这是我遵循的一般规则。如果你传递一些大的结构,你可能会耗尽内存。如果你使用的是参考类型,那不是问题。
答案 3 :(得分:1)
我能看到的唯一显着差异在于易于打电话。
这个版本3怎么样:
void Visit(Node n)
{
DoSomethingUsefulWith(n);
Visit(n.children);
}
void Visit(List<Node> nodes)
{
foreach (Node n in nodes)
Visit(n);
}
答案 4 :(得分:1)
我认为版本2没有任何实际好处 - 只是它限制了你的功能的灵活性,因为你不能再用单个节点开始你的递归了。
Imo,版本1更容易阅读,所以我会选择第一。答案 5 :(得分:1)
我个人认为版本1更好地反映了树的递归定义(通常基于单个节点)。因此,我赞成第1版。
答案 6 :(得分:0)
在风格上,它取决于您正在递归的对象类型的根。
实际上它们是一样的。除非我的大脑在公园.......