java alogrithm: найти пред / следующий листовой узел, который удовлетворяет специальному условию из любого узла в дереве - PullRequest
1 голос
/ 03 августа 2011

Мне нужно написать функцию, чтобы найти предыдущий / следующий листовой узел, который удовлетворяет специальному условию из любого узла в одиночно укорененном дереве. (в родительском первом порядке)

API будет выглядеть примерно так:

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

, где 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();
}

А интерфейс Condition определяет семантику проверки ограничения для данного Node.

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

Мой вопрос:

Существует ли существующая библиотека или алгоритм для такого распространенного сценария? Я открыт для стековых или рекурсивных алгоритмов. Буду признателен за псевдокод, ссылки на библиотеки с открытым исходным кодом или если вы захотите поделиться собственным кодом.

(Если нет, мне нужно потратить время на то, чтобы снова изобрести то же колесо и вставить его сюда, чтобы поделиться.)

Спасибо.

----------------------------- написать метод 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;
}

------------------------ полный поиск намного проще ............

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

Ответы [ 3 ]

0 голосов
/ 03 августа 2011

Напишите итератор для вашего дерева, который можно инициализировать с любого узла и использовать обход до / в / после заказа (конечно, он должен быть двунаправленным). Это в основном написание одного простого алгоритма, который, по крайней мере, мне кажется базовым. Если у вас есть итератор, все, что вам нужно, это перебрать свой путь к следующему узлу, который является листом, и условие для него выполнено. Если у вас возникли проблемы с какой-либо конкретной частью, просто спросите, и я улучшу свой ответ.

0 голосов
/ 03 августа 2011

Исходя из того, что вы уже определили свои интерфейсы, и вы говорите, что библиотеки обхода графа слишком тяжелые, вам, вероятно, стоит написать их самостоятельно. Это было бы абсолютно тривиальным количеством кода. ( Эта страница содержит код, если вам нужна помощь.)

(Одно из предложений для вашего API: не помещайте метод boolean isRoot(); в Node, это пустая трата денег, если у вас нет веских причин для этого. Код, который создает дерево, должен просто ссылаться корневой узел.)

0 голосов
/ 03 августа 2011

Это может быть слишком преувеличено для того, что вам нужно, но оно может поддерживать то, что вы хотите:

Существует язык обхода графа: Gremlin . Как правило, прикрепляется поверх чего-то вроде Neo4j, но любая структура данных графа (например, дерево с однокорневым направлением) может быть обернута для поддержки API. Взгляните на Blueprints проектов, чтобы узнать, как это делается.

[править: для чего-то менее тяжелого]

Возможно JGraphT - это то, что вы хотите. Также взгляните на этот вопрос по SO . Это не точный дубликат, но вы должны найти его полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...