All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.graphs.core.TreeTraverser Maven / Gradle / Ivy

package cdc.graphs.core;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

import cdc.graphs.EdgeDirection;
import cdc.graphs.TraversalMethod;
import cdc.graphs.TraversalOrder;
import cdc.graphs.TreeAdapter;
import cdc.util.function.Evaluator;
import cdc.util.function.Visitor;
import cdc.util.lang.Checks;

public class TreeTraverser {
    protected final TreeAdapter adapter;

    private static final String DIRECTION = "direction";
    private static final String METHOD = "method";
    private static final String NODE = "node";
    private static final String ORDER = "order";
    private static final String VISITOR = "visitor";

    public TreeTraverser(TreeAdapter adapter) {
        this.adapter = adapter;
    }

    public final TreeAdapter getAdapter() {
        return adapter;
    }

    /**
     * Most generic traversal function.
     *
     * @param node The initial node. Must not be null.
     * @param method The traversal method. Must not be null.
     * @param order The traversal order. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node. Must not be null.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverse(N node,
                         TraversalMethod method,
                         TraversalOrder order,
                         EdgeDirection direction,
                         Visitor visitor,
                         Evaluator evaluator) {
        Checks.isNotNull(node, NODE);
        Checks.isNotNull(method, METHOD);
        Checks.isNotNull(order, ORDER);
        Checks.isNotNull(direction, DIRECTION);
        Checks.isNotNull(visitor, VISITOR);

        if (method == TraversalMethod.BREADTH_FIRST) {
            traverseBreadthFirst(node, order, direction, visitor, evaluator);
        } else {
            traverseDepthFirst(node, order, direction, visitor, evaluator);
        }
    }

    /**
     * Generic traversal, without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param method The traversal method. Must not be null.
     * @param order The traversal order. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverse(N node,
                         TraversalMethod method,
                         TraversalOrder order,
                         EdgeDirection direction,
                         Visitor visitor) {
        traverse(node, method, order, direction, visitor, null);
    }

    /**
     * Depth first traversal.
     *
     * @param node The initial node. Must not be null.
     * @param order The traversal order. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverseDepthFirst(N node,
                                   TraversalOrder order,
                                   EdgeDirection direction,
                                   Visitor visitor,
                                   Evaluator evaluator) {
        Checks.isNotNull(node, NODE);
        Checks.isNotNull(order, ORDER);
        Checks.isNotNull(direction, DIRECTION);
        Checks.isNotNull(visitor, VISITOR);

        final DepthFirstTraverser traverser = new DepthFirstTraverser(direction);
        if (order == TraversalOrder.POST_ORDER) {
            traverser.traversePost(node, visitor, evaluator);
        } else {
            traverser.traversePre(node, visitor, evaluator);
        }
    }

    /**
     * Depth first traversal without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param order The traversal order. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverseDepthFirst(N node,
                                   TraversalOrder order,
                                   EdgeDirection direction,
                                   Visitor visitor) {
        traverseDepthFirst(node, order, direction, visitor, null);
    }

    /**
     * Depth first pre order traversal.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverseDepthFirstPre(N node,
                                      EdgeDirection direction,
                                      Visitor visitor,
                                      Evaluator evaluator) {
        traverseDepthFirst(node, TraversalOrder.PRE_ORDER, direction, visitor, evaluator);
    }

    /**
     * Depth first pre order traversal without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverseDepthFirstPre(N node,
                                      EdgeDirection direction,
                                      Visitor visitor) {
        traverseDepthFirst(node, TraversalOrder.PRE_ORDER, direction, visitor, null);
    }

    /**
     * Depth first post order traversal.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverseDepthFirstPost(N node,
                                       EdgeDirection direction,
                                       Visitor visitor,
                                       Evaluator evaluator) {
        traverseDepthFirst(node, TraversalOrder.POST_ORDER, direction, visitor, evaluator);
    }

    /**
     * Depth first post order traversal without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverseDepthFirstPost(N node,
                                       EdgeDirection direction,
                                       Visitor visitor) {
        traverseDepthFirst(node, TraversalOrder.POST_ORDER, direction, visitor, null);
    }

    /**
     * Breadth first traversal.
     *
     * @param node The initial node. Must not be null.
     * @param order The traversal order. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverseBreadthFirst(N node,
                                     TraversalOrder order,
                                     EdgeDirection direction,
                                     Visitor visitor,
                                     Evaluator evaluator) {
        Checks.isNotNull(node, NODE);
        Checks.isNotNull(order, ORDER);
        Checks.isNotNull(direction, DIRECTION);
        Checks.isNotNull(visitor, VISITOR);

        final BreadthFirstTraverser traverser = new BreadthFirstTraverser(direction);
        if (order == TraversalOrder.POST_ORDER) {
            traverser.traversePost(node, visitor, evaluator);
        } else {
            traverser.traversePre(node, visitor, evaluator);
        }
    }

    /**
     * Breadth first traversal without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param order The traversal order. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverseBreadthFirst(N node,
                                     TraversalOrder order,
                                     EdgeDirection direction,
                                     Visitor visitor) {
        traverseBreadthFirst(node, order, direction, visitor, null);
    }

    /**
     * Breadth first pre order traversal.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverseBreadthFirstPre(N node,
                                        EdgeDirection direction,
                                        Visitor visitor,
                                        Evaluator evaluator) {
        traverseBreadthFirst(node, TraversalOrder.PRE_ORDER, direction, visitor, evaluator);
    }

    /**
     * Breadth first pre order traversal without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverseBreadthFirstPre(N node,
                                        EdgeDirection direction,
                                        Visitor visitor) {
        traverseBreadthFirst(node, TraversalOrder.PRE_ORDER, direction, visitor, null);
    }

    /**
     * Breadth first post order traversal.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     * @param evaluator An optional evaluator used to control traversal
     *            termination.
     */
    public void traverseBreadthFirstPost(N node,
                                         EdgeDirection direction,
                                         Visitor visitor,
                                         Evaluator evaluator) {
        traverseBreadthFirst(node, TraversalOrder.POST_ORDER, direction, visitor, evaluator);
    }

    /**
     * Breadth first post order traversal without evaluator.
     *
     * @param node The initial node. Must not be null.
     * @param direction The edge direction to follow for traversal. Must not be null.
     * @param visitor Visitor that will be invoked for each visited node.
     */
    public void traverseBreadthFirstPost(N node,
                                         EdgeDirection direction,
                                         Visitor visitor) {
        traverseBreadthFirst(node, TraversalOrder.POST_ORDER, direction, visitor, null);
    }

    private class DepthFirstTraverser {
        private final EdgeDirection direction;

        public DepthFirstTraverser(EdgeDirection direction) {
            this.direction = direction;
        }

        void traversePre(N node,
                         Visitor visitor,
                         Evaluator evaluator) {
            visitor.visit(node);
            if (Evaluator.continueTraversal(evaluator, node)) {
                if (direction == EdgeDirection.OUTGOING) {
                    for (final N child : adapter.getChildren(node)) {
                        traversePre(child, visitor, evaluator);
                    }
                } else {
                    final N parent = adapter.getParent(node);
                    if (parent != null) {
                        traversePre(parent, visitor, evaluator);
                    }
                }
            }
        }

        void traversePost(N node,
                          Visitor visitor,
                          Evaluator evaluator) {
            if (Evaluator.continueTraversal(evaluator, node)) {
                if (direction == EdgeDirection.OUTGOING) {
                    for (final N child : adapter.getChildren(node)) {
                        traversePost(child, visitor, evaluator);
                    }
                } else {
                    final N parent = adapter.getParent(node);
                    if (parent != null) {
                        traversePost(parent, visitor, evaluator);
                    }
                }
            }
            visitor.visit(node);
        }
    }

    private class BreadthFirstTraverser {
        private final EdgeDirection direction;

        public BreadthFirstTraverser(EdgeDirection direction) {
            this.direction = direction;
        }

        void traversePre(N from,
                         Visitor visitor,
                         Evaluator evaluator) {
            final Deque q = new ArrayDeque<>();
            q.addLast(from);
            while (!q.isEmpty()) {
                final N next = q.pollFirst();
                visitor.visit(next);
                if (Evaluator.continueTraversal(evaluator, next)) {
                    if (direction == EdgeDirection.OUTGOING) {
                        for (final N child : adapter.getChildren(next)) {
                            q.addLast(child);
                        }
                    } else {
                        final N parent = adapter.getParent(next);
                        if (parent != null) {
                            q.addLast(parent);
                        }
                    }
                }
            }
        }

        void traversePost(N from,
                          Visitor visitor,
                          Evaluator evaluator) {
            final List visited = new ArrayList<>();
            traversePre(from, visited::add, evaluator);
            for (int index = visited.size() - 1; index >= 0; index--) {
                final N node = visited.get(index);
                visitor.visit(node);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy