Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从子树节点聚合值的算法_Java_Algorithm - Fatal编程技术网

Java 从子树节点聚合值的算法

Java 从子树节点聚合值的算法,java,algorithm,Java,Algorithm,我有树状结构中的对象,我想从子节点聚合状态信息,并用聚合状态更新父节点。假设节点A有子节点B1、B2,B1有子节点C1、C2、C3。每个节点都有一个状态属性 现在如果C1,C2,C3都完成了,那么我想把B1标记为完成。如果C4、C5、C6、C7是完整的,则B2是完整的。当B1和B2都完成时,将A标记为完成 我可以用蛮力方法检查这些节点并进行更新,有人能提出一个有效的算法来做吗 A{ 地下一层 {C1,C2,C3}, 地下二层 {C4,C5,C6,C7} }您需要后序遍历-首先访问节点的子节点,然

我有树状结构中的对象,我想从子节点聚合状态信息,并用聚合状态更新父节点。假设节点A有子节点B1、B2,B1有子节点C1、C2、C3。每个节点都有一个状态属性

现在如果C1,C2,C3都完成了,那么我想把B1标记为完成。如果C4、C5、C6、C7是完整的,则B2是完整的。当B1和B2都完成时,将A标记为完成

我可以用蛮力方法检查这些节点并进行更新,有人能提出一个有效的算法来做吗

A{ 地下一层 {C1,C2,C3}, 地下二层 {C4,C5,C6,C7}
}

您需要后序遍历-首先访问节点的子节点,然后递归地标记节点本身

类似于(伪代码):


我看不出你能逃避“暴力”

我会使用访问者设计模式


Eli Bendersky说得对,这个问题的一般答案是后序遍历

但是,为了提高效率,您必须使用您所知道的有关问题的所有信息。例如,如果您可以允许一些“过时”,那么最好在每个节点中缓存
complete
标志和时间戳

另一种可能性是节点的内部
complete
状态很少改变。在这种情况下,向上传播完整性信息可能会更好。诸如此类:

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;
  }
}

如果您知道哪些是叶节点,那么

 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)

任何有助于节省CPU周期/内存的东西。你的树有多大?你多久做一次手术?你能容忍一些“陈腐”吗?更有效地解决这一问题的方法通常不是通过低级优化,而是利用所有关于问题的知识。你可以在一些子树中缓存结果,当一个子树变得不完整时,在树上传播“不完整”标记,等等。我有大约5000棵树。每棵树有3到4层深。每个级别可以有大约20-50个节点。我计划每天运行一次此过程。可以根据需要运行单个树的进程。看起来,对于这些数据,我可能不需要缓存,但我将探索它。感谢您提供了这些重要参数。根据更新的频率,您可以计算自上次运行以来新的/更新的节点(如果与整个数据集相比较小),并向上传播更改。否则,从头开始自上而下重新计算。是的..每个节点上最后更新的时间戳是我算法的一部分,考虑一个“设计模式”来解决一个简单的算法树遍历。天哪。。。我们的日子到了;-)由于他没有具体说明他的代码,我想我应该给他一些更“强大”的工具(-1)我看不出访问者模式如何解决树遍历问题。是客户端决定了访问(遍历),而不是访问者。访客将对遍历作出响应。鉴于访问者不会维护遍历的状态,这正是访问者模式不起作用的原因。(如果说你想做一个“StatusCompleteVisitor”之类的)。除非我遗漏了一些东西,否则我认为访问者模式将不适合这个用例。如果您不断地向上提升树的状态,那么您可以避免遍历整个树,从而用对子节点的每次更改适当地标记父节点。当然,这要求孩子知道父母,但允许你通过简单的根检查来了解整体状态。@Yuval:是的,这是一种折衷。在某些情况下,它可能更有效,这取决于您更改孩子的频率和查询状态的频率。感谢Philippe提供的全面逻辑。
 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)