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

com.landawn.abacus.guava.Traverser Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 5.3.16
Show newest version
/*
 * Copyright (C) 2017 HaiYang Li
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.landawn.abacus.guava;

import java.io.File;
import java.util.Arrays;

import com.google.common.graph.SuccessorsFunction;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.stream.Stream;

/**
 * Provides methods for traversing a graph.
 * @param  Node parameter type
 *
 * @see http://google.github.io/guava/releases/23.3-android/api/docs/
 */
public final class Traverser {

    public static final Traverser FILES = forTree(t -> {
        File[] subFiles = t.listFiles();
        return N.isNullOrEmpty(subFiles) ? N. emptyList() : Arrays.asList(subFiles);
    });

    private final com.google.common.graph.Traverser gTraverser;

    private Traverser(com.google.common.graph.Traverser gTraverser) {
        this.gTraverser = gTraverser;
    }

    /**
     * Creates a new traverser for a directed acyclic graph that has at most one path from the start
     * node to any node reachable from the start node, such as a tree.
     *
     * 

Providing graphs that don't conform to the above description may lead to: * *

    *
  • Traversal not terminating (if the graph has cycles) *
  • Nodes being visited multiple times (if multiple paths exist from the start node to any * node reachable from it) *
* * In these cases, use {@link #forGraph(SuccessorsFunction)} instead. * *

Performance notes * *

    *
  • Traversals require O(n) time (where n is the number of nodes reachable from * the start node). *
  • While traversing, the traverser will use O(H) space (where H is the number * of nodes that have been seen but not yet visited, that is, the "horizon"). *
* *

Examples * *

This is a valid input graph (all edges are directed facing downwards): * *

{@code
     *    a     b      c
     *   / \   / \     |
     *  /   \ /   \    |
     * d     e     f   g
     *       |
     *       |
     *       h
     * }
* *

This is not a valid input graph (all edges are directed facing downwards): * *

{@code
     *    a     b
     *   / \   / \
     *  /   \ /   \
     * c     d     e
     *        \   /
     *         \ /
     *          f
     * }
* *

because there are two paths from {@code b} to {@code f} ({@code b->d->f} and {@code * b->e->f}). * *

Note on binary trees * *

This method can be used to traverse over a binary tree. Given methods {@code * leftChild(node)} and {@code rightChild(node)}, this method can be called as * *

{@code
     * Traverser.forTree(node -> ImmutableList.of(leftChild(node), rightChild(node)));
     * }
* * @param * @param tree {@link SuccessorsFunction} representing a directed acyclic graph that has at most * one path between any two nodes * @return */ public static Traverser forTree(final Function> tree) { return new Traverser<>(com.google.common.graph.Traverser.forGraph(node -> tree.apply(node))); } /** * Creates a new traverser for the given general {@code graph}. * *

If {@code graph} is known to be tree-shaped, consider using {@link * #forTree(SuccessorsFunction)} instead. * *

Performance notes * *

    *
  • Traversals require O(n) time (where n is the number of nodes reachable from * the start node), assuming that the node objects have O(1) {@code equals()} and * {@code hashCode()} implementations. *
  • While traversing, the traverser will use O(n) space (where n is the number * of nodes that have thus far been visited), plus O(H) space (where H is the * number of nodes that have been seen but not yet visited, that is, the "horizon"). *
* * @param * @param graph {@link SuccessorsFunction} representing a general graph that may have cycles. * @return */ public static Traverser forGraph(final Function> graph) { return new Traverser<>(com.google.common.graph.Traverser.forGraph(node -> graph.apply(node))); } /** * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in * the order of a breadth-first traversal. That is, all the nodes of depth 0 are returned, then * depth 1, then 2, and so on. * *

Example: The following graph with {@code startNode} {@code a} would return nodes in * the order {@code abcdef} (assuming successors are returned in alphabetical order). * *

{@code
     * b ---- a ---- d
     * |      |
     * |      |
     * e ---- c ---- f
     * }
* *

The behavior of this method is undefined if the nodes, or the topology of the graph, change * while iteration is in progress. * *

The returned {@code Iterable} can be iterated over multiple times. Every iterator will * compute its next element on the fly. It is thus possible to limit the traversal to a certain * number of nodes as follows: * *

{@code
     * Iterables.limit(Traverser.forGraph(graph).breadthFirst(node), maxNumberOfNodes);
     * }
* *

See Wikipedia for more * info. * * @param startNode * @return * @throws IllegalArgumentException if {@code startNode} is not an element of the graph */ public Stream breadthFirst(T startNode) { return Stream.of(gTraverser.breadthFirst(startNode).iterator()); } /** * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in * the order of a depth-first pre-order traversal. "Pre-order" implies that nodes appear in the * {@code Iterable} in the order in which they are first visited. * *

Example: The following graph with {@code startNode} {@code a} would return nodes in * the order {@code abecfd} (assuming successors are returned in alphabetical order). * *

{@code
     * b ---- a ---- d
     * |      |
     * |      |
     * e ---- c ---- f
     * }
* *

The behavior of this method is undefined if the nodes, or the topology of the graph, change * while iteration is in progress. * *

The returned {@code Iterable} can be iterated over multiple times. Every iterator will * compute its next element on the fly. It is thus possible to limit the traversal to a certain * number of nodes as follows: * *

{@code
     * Iterables.limit(
     *     Traverser.forGraph(graph).depthFirstPreOrder(node), maxNumberOfNodes);
     * }
* *

See Wikipedia for more info. * * @param startNode * @return * @throws IllegalArgumentException if {@code startNode} is not an element of the graph */ public Stream depthFirstPreOrder(T startNode) { return Stream.of(gTraverser.depthFirstPreOrder(startNode).iterator()); } /** * Returns an unmodifiable {@code Iterable} over the nodes reachable from {@code startNode}, in * the order of a depth-first post-order traversal. "Post-order" implies that nodes appear in the * {@code Iterable} in the order in which they are visited for the last time. * *

Example: The following graph with {@code startNode} {@code a} would return nodes in * the order {@code fcebda} (assuming successors are returned in alphabetical order). * *

{@code
     * b ---- a ---- d
     * |      |
     * |      |
     * e ---- c ---- f
     * }
* *

The behavior of this method is undefined if the nodes, or the topology of the graph, change * while iteration is in progress. * *

The returned {@code Iterable} can be iterated over multiple times. Every iterator will * compute its next element on the fly. It is thus possible to limit the traversal to a certain * number of nodes as follows: * *

{@code
     * Iterables.limit(
     *     Traverser.forGraph(graph).depthFirstPostOrder(node), maxNumberOfNodes);
     * }
* *

See Wikipedia for more info. * * @param startNode * @return * @throws IllegalArgumentException if {@code startNode} is not an element of the graph */ public Stream depthFirstPostOrder(T startNode) { return Stream.of(gTraverser.depthFirstPostOrder(startNode).iterator()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy