遍历无序二叉树

时间:2011-11-05 05:13:23

标签: tree parallel-processing

我遇到需要以并行方式访问树的情况。 这怎么可能?没有递归,我无法想到任何树木。

1 个答案:

答案 0 :(得分:0)

不确定您是否还在寻找答案,但我认为其他人可能会受益。

你仍然可以使用递归,但你需要锁定树的分支,并允许其他线程跳过'那些分支,因为它们已经(或已经被)处理过。

例如,假设您正在处理执行广度优先遍历的树,因此在每次运行递归方法时,您将遍历当前节点的子节点。每个线程必须遍历当前节点的子节点并尝试锁定每个子节点,如果它已被锁定则跳过它。

我不确定您使用的是哪种树实现,因此您应该对待节点'以下示例中的对象代码为伪代码,但其余的是正确的Java。

在下面的示例中,选择预定深度以应用锁定 - 这可确保线程不会简单地锁定树的根并序列化对整个树的访问。

选择正确的深度取决于特定树的形状。例如,如果它是一个二叉树,那么你的树在深度3可能有多达8个分支,这对于几个线程来说很可能是好的,但如果你运行20个线程,你需要选择一个序列化点较低的深度,以确保所有线程都能够处理一些分支。

您还可以使用其他一些方法来决定何时锁定(例如,如果节点可以有效地报告它有多少个叶子节点,您可以在其上设置阈值),重要的是所有线程都使用相同的代码决定锁定或不锁定。

Object master_LOCK = new Object();
HashMap locks = new HashMap();
int DEPTH = 5;

public boolean lockNode(Object nodeID) {
    synchronized(master_LOCK) {
        Object node_LOCK = (Object)locks.get(nodeID);
        if (node_LOCK == null) {
            //we can lock this node
            locks.put(nodeID,new Object());
            return true;
        } else {
            //node already locked
            return false;
        }
    }
}

public void traverseBreadhFirst(Node node) {    
    locks.clear();
    traverseBreadthFirst(node,0);
}

public void traverseBreadthFirst(Node node, int currentDepth) {
    currentDepth++;

    //Process the current node here


    //Iterate through children, locking to force serialised access only at a predetermined depth
    List children = node.getChildren();

    for (int i = 0; i < children.size(); i++) {

        Node child = (Node)children.get(i);

        //If we are a certain depth in the tree we start serialising access from that point on
        //This ensures that there are enough branches at this point to roughly evenly distribute them 
        //to all available threads.

        if (currentDepth < DEPTH ) {
            //All threads are to go to depth N
            traverseBreadthFirst(node,currentDepth);

        } else if (currentDepth == DEPTH ) {
            //At depth N we lock all branches we intend to process
            if (lockNode(child.getID())) {
                //We have locked this child node so we should process it
                traverseBreadthFirst(node,currentDepth);
            } else {
                //This child has been locked for processing already so we skip it
            }

        } else {
            //We are deeper than depth N so we can traverse our locked branch without locking further
            traverseBreadthFirst(node,currentDepth);

        }
    }

}