简体   繁体   English

二叉树,其中每个节点的值包含子节点的总和

[英]Binary tree where value of each node holds the sum of child nodes

This question was asked of me in an interview. 在接受采访时我问过这个问题。 How can we convert a BT such that every node in it has a value which is the sum of its child nodes? 我们如何转换BT以使其中的每个节点都具有一个值,该值是其子节点的总和?

Give each node an attached value. 为每个节点提供附加值。 When you construct the tree, the value of a leaf is set; 构造树时,设置叶子的值; construct interior nodes to have the value leaf1.value + leaf2.value . 构造内部节点的值为leaf1.value + leaf2.value

If you can change the values of the leaf nodes, then the operation has to go "back up" the tree updating the sum values. 如果您可以更改叶节点的值,则操作必须“备份”更新总和值的树。

This will be a lot easier if you either include back links in the nodes, or implement the tree as a " threaded tree ". 如果要么在节点中包含反向链接,要么将树实现为“ 线程树 ”,这将更容易。

Here is a solution that can help you: (the link explains it with tree-diagrams) 这是一个可以帮助您的解决方案:(链接用树形图解释)

Convert an arbitrary Binary Tree to a tree that holds Children Sum Property 将任意二进制树转换为包含Children Sum属性的树

/* This function changes a tree to to hold children sum
   property */
void convertTree(struct node* node)
{
  int left_data = 0,  right_data = 0, diff;

  /* If tree is empty or it's a leaf node then
     return true */
  if(node == NULL ||
     (node->left == NULL && node->right == NULL))
    return;
  else
  {
    /* convert left and right subtrees  */
    convertTree(node->left);
    convertTree(node->right);

    /* If left child is not present ten 0 is used
       as data of left child */
    if(node->left != NULL)
      left_data = node->left->data;

    /* If right child is not present ten 0 is used
      as data of right child */
    if(node->right != NULL)
      right_data = node->right->data;

    /* get the diff of node's data and children sum */
    diff = left_data + right_data - node->data;

    /* If node's data is smaller then increment node's data
       by diff */
    if(diff > 0)
       node->data = node->data + diff;

    /* THIS IS TRICKY --> If node's data is greater then increment left
      subtree  by diff */
    if(diff < 0)
      increment(node->left, -diff);
  }
}

See the link to see the complete solution and explanation! 请参阅链接以查看完整的解决方案和说明!

Well as Charlie pointed out, you can simply store the sum of respective subtree sizes in each inner node, and have leaves supply constant values at construction (or always implicitly use 1, if you're only interested in the number of leaves in a tree). 正如Charlie指出的那样,你可以简单地在每个内部节点中存储各个子树大小的总和,并在构造时提供常量值(或者如果你只对树中的叶子数感兴趣,则总是隐式使用1) )。

This is commonly known as an Augmented Search Tree. 这通常称为增强搜索树。

What's interesting is that through this kind of augmentation, ie, storing additional per-node data, you can derive other kinds of aggregate information for items in the tree as well. 有趣的是,通过这种扩充,即存储额外的每节点数据,您还可以为树中的项目导出其他类型的聚合信息。 Any information you can express as a monoid you can store in an augmented tree, and for this, you'll need to specify: 您可以表示为可以存储在增强树中的monoid的任何信息,为此,您需要指定:

  1. the data type M; 数据类型M; in your example, integers 在你的例子中,整数
  2. a binary operation "op" to combine elements, with M op M -> M; 二元运算“op”组合元素,M op M - > M; in your example, the common "plus" operator 在您的示例中,常见的“加号”运算符

So besides subtree sizes, you can also express stuff like: 所以除了子树大小,你还可以表达如下内容:

  • priorities (by way of the "min" or "max" operators), for efficient queries on min/max priorities; 优先级(通过“min”或“max”运算符),用于有效查询最小/最大优先级;
  • rightmost elements in a subtree (ie, an "op" operator that simply returns its second argument), provided that the elements you store in a tree are ordered somehow. 子树中最右边的元素(即,只是返回其第二个参数的“op”运算符),前提是存储在树中的元素以某种方式排序。 Note that this allows us to view even regular search trees (aka. dictionaries -- "store this, retrieve that key") as augmented trees with a corresponding monoid. 请注意,这允许我们甚至可以查看常规搜索树(也称为词典 - “将此存储,检索该键”)作为具有相应幺半群的扩充树。

(This concept is rather reminiscent of heaps, or more explicitly treaps, which store random priorities with inner nodes for probabilistic balancing. It's also quite commonly described in the context of Finger Trees, although these are not the same thing.) (这个概念让人联想到堆,或更明确的treaps,它存储随机优先级与内部节点进行概率平衡。它也常见于Finger Trees的上下文中,尽管这些并不相同。)

If you also provide a neutral element for your monoid, you can then walk down such a monoid-augmented search tree to retrieve specific elements (eg, "find me the 5th leaf" for your size example; "give me the leaf with the highest priority"). 如果你还为你的幺半群提供一个中性元素,那么你可以走下这样一个幺半群增强的搜索树来检索特定的元素(例如,“找到我的第五片叶子”为你的大小例子;“给我最高的叶子优先”)。

Uhm, anyways. 嗯,反正。 Might have gotten carried away a bit there.. I just happen to find that topic quite interesting. 可能会在那里被带走......我碰巧发现这个话题非常有趣。 :) :)

Here is the code for the sum problem. 这是总和问题的代码。 It works i have tested it. 它的工作原理我测试过它。

int sum_of_left_n_right_nodes_4m_root(tree* local_tree){

   int left_sum = 0;
   int right_sum = 0;
   if(NULL ==local_tree){
       return 0;
   }   
   if((NULL == local_tree->left)&&(NULL == local_tree->right)){
       return 0;
   }   
   sum_of_left_n_right_nodes(local_tree->left);
   sum_of_left_n_right_nodes(local_tree->right);
   if(NULL != local_tree->left)
       left_sum = local_tree->left->data + 
                  local_tree->left->sum;

   if(NULL != local_tree->right)
       right_sum = local_tree->right->data + \ 
                   local_tree->right->sum;

       local_tree->sum= right_sum + left_sum;


}

使用递归函数,您可以通过使每个节点的值等于它的子节点的值的总和,条件是它有两个子节点,或者它的单个子节点的值(如果它有一个子节点),如果它有没有孩子(叶子),那么这是破坏条件,价值永远不会改变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM