简体   繁体   English

java alogrithm:从树中的任何节点中找到满足特殊条件的前/后叶节点

[英]java alogrithm: find pre/next leaf node that meet special condition from any node in a tree

I need to write a function to find previous/next leaf node that meet special condition from any node in a singly rooted tree. 我需要编写一个函数来从单根树中的任何节点中找到满足特殊条件的上一个/下一个叶子节点。 (in the parent first order) (以父级第一顺序)

The API would be something like this: 该API将如下所示:

Node findNextLeafNode(Node currentNode, Condition condition);
Node findPretLeafNode(Node currentNode, Condition condition);

where currentNode is any node in a tree, and Node is defined as: 其中currentNode是树中的任何节点,而Node定义为:

interface Node{
    /** @return the Node's parent or null if Node is root */ 
    Node getParent();

    /** @return true if node is root */
    boolean isRoot();

    /** @return non-null array of child nodes (zero length for leaf nodes) */
    Node[] getChildren();

    /** @return the number of child nodes. If node is leaf, value is 0 */
    int getChildCount();
}

And the Condition interface defines the semantics of checking a constraint against a given Node . Condition接口定义检查针对给定Node的约束的语义。

interface Condition{
  /** @return true if provided node meets the condition */
  boolean check(Node node);
}

My question: 我的问题:

Is there an existing library or algorithm for such a common scenario? 是否存在用于这种常见情况的现有库或算法? I am open to either stack based or recursive algorithms. 我对基于堆栈或递归算法很开放。 Pseudocode, links to open source libraries, or if you care to share you own code, would be appreciated. 伪代码,到开源库的链接,或者如果您愿意共享自己的代码,将不胜感激。

(If not, I need to spend time to invent the same wheel again and paste it here later for sharing.) (如果没有,我需要花时间再次发明相同的轮子,然后将其粘贴到此处以便共享。)

Thanks. 谢谢。

-----------------------------write a method to getNext()........ -----------------------------编写getNext()方法........

// currentNode must be descendant of root
public static Node getNextNode(Node currentNode, Node root)
{
    // 1. if is has child, next is its first child
    if (currentNode.getChildSize() > 0) {
        return currentNode.getChildren()[0];
    }
    // 2. if it has no child, check if its is the last child of his parent
    else {
        // if it is root and has no children, return null
        if (currentNode == root) {
            return null;
        }

        // else should have parent which is or under root;
        Node parent = currentNode.getParent();
        int index = getIndex(currentNode);

        if (!isLastofParent(currentNode)) {
            // ----a. if not last, next is his parent's next
            return currentNode.getParent().getChildren()[index + 1];
        }
        else {
            // ----b. if it is the last one, return its parent's next right if there is. while until root
            Node tmp = parent;
            while (tmp != root) {
                int parentIndex = getIndex(tmp);
                if (!isLastofParent(tmp)) {
                    return tmp.getParent().getChildren()[parentIndex + 1];
                }
                tmp = tmp.getParent();
            }
        }
    }
    return null;

}

private static boolean isLastofParent(Node node)
{
    if (getIndex(node) == node.getParent().getChildSize() - 1) {
        return true;
    }
    return false;
}

private static int getIndex(Node currentNode)
{
    Node parent = currentNode.getParent();
    for (int i = 0; i < parent.getChildSize(); i++) {
        if (parent.getChildren()[i] == currentNode) {
            return i;
        }
    }
    //TODO: error condition handling, will not happen if tree not change
    return -1;
}

------------------------a full search is much easier............ ------------------------全面搜索要容易得多............

public static Node getNextFailNode(Node currentNode, Node root, Condition condition)
{
    boolean foundCurrentNode = false;
    Stack<Node> stack = new Stack<Node>();
    stack.push(root);
    while (!stack.isEmpty()) {
        Node tmp = stack.pop();
        System.out.println("-popup---------" +tmp+ " ");
        if (foundCurrentNode && checkCondition(tmp, condition)) {
            return tmp;
        }
        if (tmp == currentNode) {
            foundCurrentNode = true;
        }
        if (tmp.getChildSize() > 0) {

            for (int i = tmp.getChildSize() - 1; i >= 0; i--) {
                stack.push(tmp.getChildren()[i]);
            }
        }

    }
    return null;
}

This maybe way overblown for what you need, but it can support what you want: 对于您的需求,这可能有些夸大其词,但它可以满足您的需求:

There is a graph traversal language: Gremlin . 有一种图形遍历语言: Gremlin Typically bolted on top of something like Neo4j, but any graph data structure (eg a singly rooted directed tree) can be wrapped to support the API. 通常用螺栓固定在Neo4j之类的物体上,但是可以包装任何图形数据结构(例如,单根有向树)以支持API。 Take a look at Blueprints projects to find out how it is done. 查看Blueprints项目,以了解如何完成。

[edit: for something less heavy] [编辑:减轻一些重量]

Perhaps JGraphT is what you want. 也许JGraphT是您想要的。 Also take a look at this question on SO . 还可以看看关于SO的这个问题 It is not an exact duplicate, but you should find it helpful. 它不是完全相同的副本,但您会发现它有帮助。

Write an iterator for your tree that can be initialized from any node and uses pre/in/post-order traversal (Of course it should be bi-directional). 为您的树编写一个迭代器,该迭代器可以从任何节点初始化并使用前/后/后顺序遍历(当然,它应该是双向的)。 This is basically writing one simple algorithm that at least to me seem basic. 基本上,这是在编写一种简单的算法,至少对我来说,这是基本的。 Once you have an iterator all you need is to iterate your way to the next node which is a leaf and the condition holds for it. 有了迭代器后,您所需要做的就是将您的方法迭代到下一个节点,该节点是叶子,并且条件满足该条件。 If you have trouble with any specific part just ask and I'll improve my answer. 如果您在任何特定部分上遇到问题,请提出问题,我会改善答案。

Based on the fact that you already have defined your interfaces, and you say the graph-traversal libraries are too heavyweight, you probably should just write it yourself. 基于您已经定义了接口,并且您说图形遍历库太重的事实,您可能应该自己编写。 It would be an absolutely trivial amount of code. 这绝对是微不足道的代码。 ( This page contains some code if you need help.) (如果需要帮助, 此页面包含一些代码。)

(One suggestion for your API: don't put a boolean isRoot(); method on Node , that's a waste of bits unless you have a very good reason to do so. The code that builds the tree should just refer to the root node.) (对您的API的一个建议是:不要在Node上放置一个boolean isRoot();方法,除非您有充分的理由这样做,否则这会浪费一些位。构建树的代码应仅引用根节点)

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

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