tags:

views:

98

answers:

4

I have objects in a tree structure, I would like to aggregate status information from children nodes and update parent node with aggregated status. Lets say node A has children B1, B2, and B1 has C1, C2, C3 as children. Each of the nodes have a status attribute.

Now if C1, C2, C3 are all complete then I would like to mark B1 as completed. And if C4, C5,C6,C7 are complete make B2 as complete. When B1 and B2 are both complete mark A as complete.

I can go through these nodes in brute force method and make updates, could someone suggest an efficient algorithm to do it.

A { B1 { C1, C2, C3}, B2 { C4, C5, C6, C7} }

+2  A: 

You need post-order traversal - first visit the children of a node, then mark the node itself, recursively.

Something like (pseudocode):

iscomplete(node):
  if node == Null:
     return False
  elsif no children:
     return some "complete" value according to node value
  else:
     for child in node.children:
         if not iscomplete(child):
             return False

  return True
Eli Bendersky
You can avoid traversing the entire tree if you continuously pump the status up the tree, thereby marking the parent node appropriately with every change to the child. This requires the child to know the parent, of course, but allows you to find out the overall status with a simple check of the root.
Yuval
@Yuval: yes, this is a tradeoff. It can be more efficient in some situations, depending on how often you change children and how often you query the status.
Eli Bendersky
@Yuval: See my answer below for some pseudocode for this.
Philippe Beaudoin
A: 

I can't see that you can evade "brute force".

I would use the visitor design pattern.

http://www.javaworld.com/javaworld/javatips/jw-javatip98.html

http://sourcemaking.com/design_patterns/visitor

Yaneeve
Using a "design pattern" for solving a trivial algorithmic tree traversal. Geez... what days are upon us ;-)
Eli Bendersky
Since he had not been specific about his code, I figured I would hand him more "powerful" tools
Yaneeve
(-1) I fail to see how tree traversal can be solved by a visitor pattern.
harschware
Point well made, yet I would still encapsulate the traversal within a visitor...
Yaneeve
It's the client that dictates the visiting(traversal), not the visitor. The visitor would respond to a traversal. Given the visitor would not maintain state about the traversal, this is exactly why a visitor pattern would not help. ( If say you were trying to make a "StatusCompleteVisitor" or some such). Unless I'm missing something I think the visitor pattern is just not going to fit this use case.
harschware
+2  A: 

Eli Bendersky has it right, the general answer to this problem is post-order traversal.

For more efficiency, though, you have to use everything you know about the problem. For example, if you can allow some "staleness" then it might be better to cache a complete flag and a timestamp in each node.

Another possibility is that the internal complete status of nodes rarely changes. In this case, it might be much better to propagate up completeness information. Something like that:

class NodeWithCompletenessInfo : public Node {

  private bool internalComplete; // Am I personally done?
  private bool childrenComplete; // Are my children done?

  public bool isComplete() {
    return internalComplete && childrenComplete;
  }

  public void markComplete() {
    internalComplete = true;
    if( isComplete() )
      parent.markChildComplete();
  }

  public void markIncomplete() {
    if( isComplete() )
      parent.markChildIncomplete();
    internalComplete = false;
  }

  private void markChildComplete() {
    for( child in children ) {
      if( !child.isComplete() )
        return;
      childrenComplete = true;
    }
    if( isComplete() )
      parent.markChildComplete()
  }

  private void markChildIncomplete() {
    if( isComplete() )
      parent.markChildIncomplete();
    this.childrenComplete = false;
  }
}
Philippe Beaudoin
Thanks Philippe for the comprehensive logic.
tech20nn
A: 

If you know which are leaf nodes then

 A { 
    B1 
        {C1, C2 = false, C3},
    B2 
        {C4, C5=false, C6=false, C7} 
  } // those not marked false are true ;)

not_complete_leaf_nodes_with_different_parents = [ C2 , C5]

mark_not_complete(node):
    node.complete = false
    if parent != null
        mark_not_complete(node.parent)

for each in not_complete_leaf_nodes_with_different_parents:
    mark_not_complete(each.parent)
TheMachineCharmer