【问题标题】:How does this function count the number of nodes in a tree?此函数如何计算树中的节点数?
【发布时间】:2011-08-19 06:03:19
【问题描述】:

计算树中节点数的函数。

int count(node *t)
{    
    int i;  
    if (t == NULL)         
        return(0);  
    i = 1 + count(t->left) + count(t->right); // recursion occurs address of left node is passed and 
    return(i);                                // continue to pass until whole left node
}                                             // is traversed and the value of t is
                                              // NULL and 0 is returned same for right node counting
                                              // i = 1 + 0 + 0 = 1

节点数是怎么统计的?

【问题讨论】:

  • 左节点是子树。右节点也是一个子树。函数正在调用自身,子树作为参数并且计数递增。现在,当计数器到达叶子时,它没有任何子节点,所以它返回 0。意思是 leaf tree has count one。现在它上升了一级,结果是1 + left leaf count + right leaf count) = 3。同样,它又上一级并获得总数。 假设所有节点除了叶子之外都有左右子节点。嗯,概念不变

标签: c recursion tree


【解决方案1】:
【解决方案2】:

这是计算树节点的递归实现。它为根节点调用并返回“左子树中的节点数加上右子树中的节点数”,递归完成,直到它到达叶节点。

【讨论】:

  • 我所知道的是它递归遍历左子树直到找到最后一个节点现在 t 的值为 NULL 并且在 count(t->left) 处返回的值为零相同子树并返回 0 到 count(t->right)。现在加法发生 i=1+0+0=1;那么它如何计算左右节点的总数
  • @srbh:关键是一旦递归调用开始,前一个调用将保持“暂停”并等待递归调用结束,然后使用其结果。所以调用树首先下到叶子节点,然后调用开始以 FIFO 顺序返回,并总结子树的节点数。
  • 表示为递归调用维护一个堆栈,并继续压入每个节点的地址,直到找到空节点。然后它去 count(t->right) 找到正确的节点,直到找到 NULL 节点。节点的先前地址被弹出,现在又回到它的父节点,左右节点被计数,依此类推。请纠正我的错误。
【解决方案3】:

总计数包括当前/根节点加上左分支的计数加上右分支的计数。您的哨兵是 NULL,这意味着您已到达当前计数的任何分支的叶节点。然后你放松回来。递归:)

【讨论】:

    【解决方案4】:

    首先,你自己试过了吗?

    基本上,它为每个非空节点加 1。大致是这样的:1 + number_of_nodes_to_the_left + number_of_nodes_to_the_right。这扩展为:1+(1+number_of_nodes_to_the_left_in_left+number_of_nodes_to_the_right_in_left) + (1+number_of_nodes_to_the_left_in_right + number_of_nodes_to_the_right_in_right)。继续扩展,您会发现对于树中的每个非空节点,它基本上都是 1 + 1 + 1 +....

    编辑:为了更好地说明这一点,请考虑以下树:

         Node0
           |
    (left) |  (right)
    Node1 _|_ Node2
                |
         (left) |  (right)
         Node3 _|_ Node4
    

    当您执行int node_count = count(Node0) 时,由于 Node0 不为 NULL,它会转到 return 语句,即: return 1 + count(left) + count(right)。您需要了解一个基本的事情,即递归函数中的操作一个接一个地发生。换句话说,操作count(right) 直到操作count(left) 完成后才会发生。现在看看你那里的 return 语句,并根据上面的树翻译它。应该是1+count(Node1)+count(Node2)。所以count(Node2)count(Node1) 完成之前不会被计算。所以对于count(Node1),count 函数被调用(再次)以 Node1 作为参数。所以,让我们暂时忘记半计算表达式1+count(Node1)+count(Node2)(我们稍后再讨论)。

    现在对于count(Node1),Node1 不为 NULL,因此继续执行 return 语句。这将(再次)是1+count(left)+count(right)。但是等等,Node1 没有左右节点。因此,当count(left) 被调用且参数为NULL 时,它返回0 并且count(right) 也会发生同样的情况。所以count(Node1) 的表达式变为1 + 0 + 0。不再为 Node1 调用计数函数,因此它返回到原来的调用者,这是count(Node0) 的返回语句

    既然我们已经找到了count(Node1),让我们在count(Node0) 的返回语句中替换它。现在变成1 + (1 + 0 + 0) + count(Node2)

    现在我要加快速度。由于 Node2 有两个子节点,因此 Node2 的返回语句将是 1 + count(Node3) + count(Node4)。就像 Node1 一样,count(Node3)count(Node4) 将分别返回 1 + 0 + 0,将 count(Node2) 的返回语句变为 1 + (1 + 0 + 0) + (1 + 0 + 0)

    既然count(Node2)已经计算完毕,我们回到count(Node2)的原始调用者,也就是1 + (1 + 0 + 0) + count(Node2)。替换我们从count(Node2) 那里得到的东西,我们得到1 + (1+0+0) + (1 + (1+0+0) + (1+0+0))。把它加起来,我们得到5 的值。 这个值会返回给调用count(Node0)的函数,就像语句int node_count = count(Node0)node_count的值是5

    【讨论】:

    • 我认为我的递归概念不好。但在此递归调用中,count(t->left) 继续调用自身并仅在传递左节点的地址时继续到左节点,最后找到一个空值,它将零返回给 count(t->left).now "t " 有一个 NULL 值它如何返回以计算正确的节点。请回复。
    • 我添加了更多细节。
    【解决方案5】:

    考虑这些树:

    没有节点的树(即 NULL 指针) - 返回 0

    一棵树,只有一个节点,即根。这将调用:

     i=1+count(t->left)+count(t->right);
    

    左右为NULL,所以会返回1 + 0 + 0

    一棵有根和一个右叶的树

     i=1+count(t->left)+count(t->right);
    

    将返回 1 表示根,0 表示以左边为根的树(根据上面的规则),1 表示以右边为根的树(根据上面的规则),即 1 + 0 + 1

    等等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-20
      相关资源
      最近更新 更多