【问题标题】:How many nodes have only one child in a binary tree?一棵二叉树中有多少个节点只有一个孩子?
【发布时间】:2018-12-17 14:31:50
【问题描述】:

我想计算一棵二叉树中有多少节点只有一个孩子。我不知道这样行不行。另外我不知道我是否必须使用像 postorder 这样的树搜索。

size_t tree_one_child(const tree_t* t){
if(!t || number_children(t)==0){
    return 0;
}
if(number_children(t)==1){
    return 1 + tree_one_child(t->left) + tree_one_child(t->right);
}
else{
    return tree_one_child(t->left) + tree_one_child(t->right);
}



size_t number_children(const tree_t* t){
int count = 0;
if(t->left != null ) count++;
if(t->right != null) count++;       
return count;
}

【问题讨论】:

  • 您是否只考虑直系子女或任何“孙子女”?
  • 这看起来不错。
  • 我觉得很好。
  • 只是直系子女

标签: c recursion struct tree binary-tree


【解决方案1】:

对您的代码的一些说明:

您可以将if(!t || number_children(t)==0) 简化为if(!t)。

为了避免重复自己,你应该将孩子的递归计算保存在一个变量中:

size_t tree_one_child(const tree_t* t){
    if(!t)
        return 0;

    size_t ret = tree_one_child(t->left) + tree_one_child(t->right);
    if (number_children(t) == 1)
        ret++;
    return ret;
}

除非您在其他地方使用 number_children,否则您可以改用它:

size_t one_child(const tree_t* t){
    return !t->left != !t->right;
}

表达式!a != !b 是一种执行逻辑异或的方法,这正是您想要的。它使代码更简洁。

size_t tree_one_child(const tree_t* t){
    if(!t)
        return 0;

    size_t ret = tree_one_child(t->left) + tree_one_child(t->right);
    if (one_child(t))
        ret++;
    return ret;
}

为了使这段代码更短,你可以这样做:

size_t tree_one_child(const tree_t* t){
    if(!t)
        return 0;
    return one_child(t) + tree_one_child(t->left) + tree_one_child(t->right);
}

有些人可能会争辩说这种 id 不好的做法,因为布尔值之间的加法(我知道one_child 在技术上返回一个 size_t,但它显然意味着被视为真/假)并没有真正的意义。它恰好可以正常工作,因为它在 true 时返回 1,在 false 时返回 0。

你的代码可以工作吗?

据我所见,它似乎可以完成这项工作,而且我看不到任何会产生错误结果或做坏事的情况。

关于如何说服自己的建议是编写测试。我将提供一个快速指南,告诉您如何操作。

首先,创建一个函数create_tree( .. ),从它的参数创建一个树。也许你可以有一个只接受char* 的函数,然后用那个字符串做一些魔法来生成一棵树。这样你就可以进行一些这样的测试:

void test(char * s, int expected_output) {
    tree_t * t = create_tree(s)  
    if(tree_one_child(t) == expected_output)
        printf("Test passed\n");
    else
        printf("   TEST FAILED");
    deallocate_tree(t);
}

test("1332", 3);
test("10423", 0);

注意有相当标准化的方法可以做到这一点,但我想你明白了。想办法让测试和测试代码变得容易。

【讨论】:

    【解决方案2】:

    好吧,您缺少函数 tree_one_child() 的右大括号,但除此之外,这段代码也可以工作。

    虽然风格说明:一般来说,最好只有一个地方做某项工作,例如计算您下方的一个子节点的数量;你在两个地方做。当然,当工作像recurse(left) + recurse(right) 这样简单时,它是非常安全的。但我会把这个例程写成

    size_t tree_one_child(const tree_t* t) {
        if (t == NULL)
            return 0;
        return number_children(t) + tree_one_child(t->left) + tree_one_child(t->right);
    }
    

    我认为这既更安全(因为任何人都不可能有朝一日会修改某些节点的逻辑,而不会修改其他节点的逻辑)并且更清晰。

    【讨论】:

    • 我意识到我忘了激励我的反对票。您的代码无法正常工作。对于具有两个节点的节点,它将给出错误的答案。您需要将number_children(t) 更改为(number_children(t) == 1)。不确定是否需要括号。我只是添加它们以确保。解决这个问题,我会支持你的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-22
    • 2015-12-20
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    相关资源
    最近更新 更多