我这里有两个镜像BST的算法。它们都工作正常,但据我所知,第二个是递归的,第一个是尾递归。我知道在Java中,编译器没有针对尾递归进行优化,但我的问题是 - 在任何其他语言中,这两种算法中哪种算法更好?这个问题太主观了吗?
public Node mirror(Node root, Node newRoot) {
newRoot.item = root.item;
if (root.right != null) {
newRoot.left = new Node();
newRoot.left.item = root.right.item;
mirror(root.right, newRoot.left);
}
if (root.left != null) {
newRoot.right = new Node();
newRoot.right.item = root.left.item;
mirror(root.left, newRoot.right);
}
return newRoot;
}
///VERSION 2////
public Node mirror(Node currentNode) {
if (currentNode == null) {
return null;
} else {
Node newnode = new Node();
newnode.item = currentNode.item;
newnode.left = mirror(currentNode.right);
newnode.right = mirror(currentNode.left);
return newnode;
}
}
答案 0 :(得分:1)
一些事情:
首先,许多命令式语言不优化尾递归。这对于函数式语言来说非常常见,如果你想要这个功能,你应该使用其中一种。 Scala可能是一个很好的举措,因为它使用JVM。此外,使用Scala,您需要专门注释要使尾部递归的内容
其次,第二段代码不是尾递归。尾递归是一个相当强烈的要求:如果代码以延续传递方式解释,则递归调用必须是最后执行的操作。实际上,这意味着你的return语句必须是递归的唯一东西。例如,在类似C的伪代码中:
int factorial(int x) {
if (x == 0) return 1;
else return x*factorial(x-1);
}
这是 not 尾递归,因为乘法需要在递归调用之后但在return语句之前完成。这是一个尾递归版本:
int factorial_helper(int acc, int x) {
if (x == 0) return acc;
else return factorial_helper(acc*x, x-1);
}
int factorial(int x) { return factorial_helper(1, x); }
你可以在factorial_helper中看到递归调用返回的值正是函数返回的值 - 这就是使这个尾递归的原因。
在第二个算法中,有两个递归调用。在每次递归调用中,镜像树的地址存储在newnode中。然后返回newnode的地址(Java秘密地有指针)。所以,这不是尾递归写的,因为你没有返回递归调用的确切结果。
第三:对于这样的事情,看看哪个表现更好的最好方法是运行两者和基准:)。我没有从算法中看到任何明显的赢家(也许其他人呢?)。它看起来不会有任何渐近的差异,虽然重写它实际上是尾递归可能会加快速度。