返回递归三元怪胎

时间:2010-03-15 06:49:40

标签: c++ recursion binary-tree

假设以下功能:

int binaryTree::findHeight(node *n) {
    if (n == NULL) {
        return 0;
    } else {
        return 1 + max(findHeight(n->left), findHeight(n->right));
    }
}

给定二叉搜索树treeHeight的标准递归binaryTree函数。现在,我正在帮助一个朋友(他正在参加算法课程),我遇到了一个奇怪的问题,我无法100%向他解释这个功能。

将max定义为max(a,b) ((a)>(b)?(a):(b))(恰好是windef.h中的最大定义),递归函数变得怪异(它运行n^nn是树高)。这显然使得用3000个元素检查树的高度需要非常长的时间。

但是,如果通过模板定义max,就像std那样,一切都没问题。因此使用std::max解决了他的问题。我只想知道原因。

另外,为什么countLeaves函数使用相同的程序递归工作正常?

int binaryTree::countLeaves(node *n) {
    if (n == NULL) {
        return 0;
    } else if (n->left == NULL && n->right == NULL) {
        return 1;
    } else {
        return countLeaves(n->left) + countLeaves(n->right);
    }
}

是否因为在返回三元函数时,值a => countLeaves(n->left)b => countLeaves(n->right)被递归地双重调用只是因为它们是结果?

谢谢!

问题已在下面解答

我只想链​​接一些有关该主题的文献以供将来参考:
http://www.boostpro.com/tmpbook/preprocessor.html
http://msdn.microsoft.com/en-us/library/z3f89ch8.aspx

两种实现的主要区别在于:

#define max(i, j) (((i) > (j)) ? (i) : (j))

VS

template<class T> T max (T i, T j) { return ((i > j) ? i : j) }

谢谢大家!

4 个答案:

答案 0 :(得分:11)

在编译器查看代码之前,预处理器会扩展宏。这意味着,例如,宏参数可能会被多次评估。

使用你的宏,你最终会得到类似于:

的东西
int binaryTree::findHeight(node *n) {
    if (n == NULL) {
        return 0;
    } else {
        return 1 + (findHeight(n->left) > findHeight(n->right)) ? // call once...
                    findHeight(n->left) : findHeight(n->right); // and ouch
    }
}

正如您所看到的,它将评估这两个功能,然后再花费一个额外的时间。这就是为什么宏可能是邪恶的。

您可以在包含Windows标头之前定义NOMINMAX来禁用宏。然后使用<algorithm>中的函数。

如果他必须使用宏,他必须将计算存储在一个变量中:

int binaryTree::findHeight(node *n) {
    if (n == NULL) {
        return 0;
    } else {
        const int leftHeight = findHeight(n->left);
        const int rightHeight = findHeight(n->right);
        return 1 + max(leftHeight, rightHeight);
    }
}

使用一个函数,每个调用将在之前进行评估,以调用该函数。也就是说,它有点像以前的代码块。它评估函数的参数,获取结果,然后将它们传递给std::max函数。没有重复的评估。

答案 1 :(得分:2)

max max对参数进行两次计算 - 因为你的参数是一个递归函数调用,这可能是perf问题的根源。

答案 2 :(得分:0)

这是因为max的定义。你正在调用findHeight()而不是2。

答案 3 :(得分:0)

更好的选择是声明具有以下签名的函数:

int max(int, int)

这将阻止宏的递归扩展。

相关问题