二叉树中有多少个节点只有一个子节点?

时间:2018-07-09 20:22:32

标签: c recursion struct tree binary-tree

我想计算一棵二叉树中有多少个节点只有一个孩子。我不知道这是否可以。另外我也不知道是否必须使用树状搜索(例如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;
}

2 个答案:

答案 0 :(得分:0)

您对代码的一些评论:

您可以将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);
}

有些人可能会认为这是不正确的做法,因为在布尔值之间加法(我知道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);

注意,有相当标准化的方法可以执行此操作,但我想您会明白的。寻找一些方法来简化代码测试和测试。

答案 1 :(得分:-1)

好吧,您缺少函数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);
}

我认为这既安全(因为不可能有一天有人会修改某些节点的逻辑,而没有其他人修改逻辑)