ConcreteDGraph.java
- package org.thegalactic.dgraph;
- /*
- * ConcreteDGraph.java
- *
- * Copyright: 2010-2015 Karell Bertet, France
- * Copyright: 2015-2016 The Galactic Organization, France
- *
- * License: http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html CeCILL-B license
- *
- * This file is part of java-lattices.
- * You can redistribute it and/or modify it under the terms of the CeCILL-B license.
- */
- import java.util.AbstractSet;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.NoSuchElementException;
- import java.util.Set;
- import java.util.SortedSet;
- import java.util.TreeMap;
- import java.util.TreeSet;
- /**
- * This class gives a standard representation for a directed graph by sets of
- * successors and predecessors.
- *
- * A directed graph is composed of
- *
- * - a treeset of node, defined by class {@link Node}; - a treemap of successors
- * that associates to each node a treeset of successors, defined by class
- * {@link Edge}; - a treemap of predecessors that associates to each node a
- * treeset of predecessors, defined by class {@link Edge}.
- *
- * This class provides methods implementing classical operation on a directed
- * graph:
- *
- * - sinks - wells - subgraph - reflexive closure and reduction - transitive
- * closure - strongly connected components - ...
- *
- * This class also provides a static method randomly generating a directed
- * graph.
- *
- * 
- *
- * @param <N> Node content type
- * @param <E> Edge content type
- *
- * @uml DGraph.png
- * !include resources/org/thegalactic/dgraph/DGraph.iuml
- * !include resources/org/thegalactic/dgraph/Edge.iuml
- * !include resources/org/thegalactic/dgraph/Node.iuml
- *
- * hide members
- * show DGraph members
- * class DGraph #LightCyan
- * title DGraph UML graph
- */
- public class ConcreteDGraph<N, E> extends AbstractDGraph<N, E> implements Cloneable {
- /*
- * ------------- FIELDS ------------------
- */
- /**
- * A set of elements.
- */
- private TreeSet<Node<N>> nodes;
- /**
- * A map to associate a set of successors to each node.
- *
- * @todo use a TreeSet for edges with a specific comparator for predecessors
- */
- private TreeMap<Node<N>, TreeSet<Edge<N, E>>> successors;
- /**
- * A map to associate a set of predecessors to each node.
- */
- private TreeMap<Node<N>, TreeSet<Edge<N, E>>> predecessors;
- /*
- * ------------- CONSTRUCTORS ------------------
- */
- /**
- * Constructs a new directed graph with an empty set of node.
- */
- public ConcreteDGraph() {
- super();
- this.nodes = new TreeSet<Node<N>>();
- this.successors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
- this.predecessors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
- }
- /**
- * Constructs a new directed graph source the specified set of nodes.
- *
- * Successors and predecessors of each nodes are initialised by an empty
- * set.
- *
- * @param set the set of nodes
- */
- public ConcreteDGraph(final SortedSet<Node<N>> set) {
- this();
- this.nodes.addAll(set);
- for (final Node<N> node : this.nodes) {
- this.successors.put(node, new TreeSet<Edge<N, E>>());
- this.predecessors.put(node, new TreeSet<Edge<N, E>>());
- }
- }
- /**
- * Constructs this component as a copy of the specified directed graph.
- *
- * @param graph the directed graph to be copied
- */
- public ConcreteDGraph(final DGraph<N, E> graph) {
- this(graph.getNodes());
- for (final Edge<N, E> edge : graph.getEdges()) {
- this.addEdge(edge);
- }
- }
- /*
- * --------------- ACCESSOR AND OVERLAPPING METHODS ------------
- */
- /**
- * Returns a clone of this component composed of a clone of each node and
- * each edge.
- *
- * @return the clone of this
- *
- * @throws java.lang.CloneNotSupportedException
- */
- @Override
- public ConcreteDGraph<N, E> clone() throws CloneNotSupportedException {
- final ConcreteDGraph<N, E> graph = (ConcreteDGraph<N, E>) super.clone();
- graph.nodes = (TreeSet) this.nodes.clone();
- graph.successors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
- graph.predecessors = new TreeMap<Node<N>, TreeSet<Edge<N, E>>>();
- for (final Map.Entry<Node<N>, TreeSet<Edge<N, E>>> entry : this.successors.entrySet()) {
- graph.successors.put(entry.getKey(), (TreeSet<Edge<N, E>>) entry.getValue().clone());
- }
- for (final Map.Entry<Node<N>, TreeSet<Edge<N, E>>> entry : this.predecessors.entrySet()) {
- graph.predecessors.put(entry.getKey(), (TreeSet<Edge<N, E>>) entry.getValue().clone());
- }
- return graph;
- }
- /**
- * Returns the set of nodes of this component.
- *
- * @return the set of nodes
- */
- public final SortedSet<Node<N>> getNodes() {
- return Collections.unmodifiableSortedSet(this.nodes);
- }
- /**
- * Returns the set of edges of this component.
- *
- * @return the set of edges
- */
- public final SortedSet<Edge<N, E>> getEdges() {
- return new Edges(this);
- }
- /**
- * Returns the set of edges successors of the specified node.
- *
- * @param node the node to search for
- *
- * @return the set of edges
- */
- public final SortedSet<Edge<N, E>> getSuccessorEdges(final Node<N> node) {
- return Collections.unmodifiableSortedSet(this.successors.get(node));
- }
- /**
- * Returns the set of edges predecessors of the specified node.
- *
- * @param node the node to search for
- *
- * @return the set of edges
- */
- public final SortedSet<Edge<N, E>> getPredecessorEdges(final Node<N> node) {
- return Collections.unmodifiableSortedSet(this.predecessors.get(node));
- }
- /**
- * Returns the set of nodes successors of the specified node.
- *
- * @param node the node to search for
- *
- * @return the set of nodes
- *
- * @todo use iterator pattern (some changes in ArrowRelation.java and
- * Lattice.java)
- */
- public final SortedSet<Node<N>> getSuccessorNodes(final Node<N> node) {
- final SortedSet<Node<N>> successorsFromNode = new TreeSet<Node<N>>();
- for (final Edge<N, E> edge : this.successors.get(node)) {
- successorsFromNode.add(edge.getTarget());
- }
- return Collections.unmodifiableSortedSet(successorsFromNode);
- }
- /**
- * Returns the set of nodes predecessors of the specified node.
- *
- * @param node the node to search for
- *
- * @return the set of nodes
- *
- * @todo use iterator pattern (some changes in ArrowRelation.java and
- * Lattice.java)
- */
- public final SortedSet<Node<N>> getPredecessorNodes(final Node<N> node) {
- final SortedSet<Node<N>> predecessorsFromNode = new TreeSet<Node<N>>();
- for (final Edge<N, E> edge : this.predecessors.get(node)) {
- predecessorsFromNode.add(edge.getSource());
- }
- return Collections.unmodifiableSortedSet(predecessorsFromNode);
- }
- /**
- * Returns, if it exists, the edge between node source and node to.
- *
- * @param source The origin node
- * @param target The destination node
- *
- * @return the found edge or null
- *
- * @todo see getNode
- */
- public final Edge<N, E> getEdge(final Node<N> source, final Node<N> target) {
- Edge<N, E> edge = null;
- if (source != null && target != null) {
- try {
- final Edge<N, E> search = new Edge<N, E>(source, target);
- edge = this.successors.get(source).subSet(search, true, search, true).first();
- } catch (NoSuchElementException ex) {
- }
- }
- return edge;
- }
- /**
- * Returns the node that is equal to the specified one.
- *
- * @param search The node to search for
- *
- * @return the found node or null
- *
- * @todo maybe use try { return this.nodes.subSet(search, true, search,
- * true).first(); } catch (NoSuchElementException e) { return null; }
- *
- */
- public final Node<N> getNode(final Node<N> search) {
- for (final Node<N> node : this.nodes) {
- if (node.equals(search)) {
- return node;
- }
- }
- return null;
- }
- /**
- * Returns the node whose content is equal to the specified one.
- *
- * @param content The content to search for
- *
- * @return the found node or null
- *
- * @todo this method is not efficient. Do we remove it or add an index on
- * DGraph using content field? Verify where it is called for migrating it if
- * necessary.
- */
- public final Node<N> getNodeByContent(final Object content) {
- for (final Node<N> node : this.nodes) {
- if (node.getContent().equals(content)) {
- return node;
- }
- }
- return null;
- }
- /**
- * Returns the node whose ident is equal to the specified one.
- *
- * @param identifier node identifier
- *
- * @return the found node or null
- */
- public final Node<N> getNodeByIdentifier(int identifier) {
- for (final Node<N> node : this.nodes) {
- if (node.getIdentifier() == identifier) {
- return node;
- }
- }
- return null;
- }
- /**
- * Returns the number of nodes of this component.
- *
- * @return the number of nodes
- */
- public final int sizeNodes() {
- return this.nodes.size();
- }
- /**
- * Returns the number of edges of this component.
- *
- * @return the number of edges
- */
- public final int sizeEdges() {
- int size = 0;
- for (final Node<N> node : this.nodes) {
- size += this.successors.get(node).size();
- }
- return size;
- }
- /*
- * --------------- NODES AND EDGES MODIFICATION METHODS ------------
- */
- /**
- * Checks if the specified node belong to this component.
- *
- * @param node the node to insert
- *
- * @return true if the node has been successfully inserted
- */
- public final boolean containsNode(final Node<N> node) {
- return this.nodes.contains(node);
- }
- /**
- * Adds the specified node to the set of node of this component.
- *
- * @param node the node to insert
- *
- * @return true if the node has been successfully inserted
- */
- public final boolean addNode(final Node<N> node) {
- if (!this.containsNode(node)) {
- this.nodes.add(node);
- this.successors.put(node, new TreeSet<Edge<N, E>>());
- this.predecessors.put(node, new TreeSet<Edge<N, E>>());
- return true;
- }
- return false;
- }
- /**
- * Removes the specified node from this component.
- *
- * @param node the node to remove
- *
- * @return true if the node was successfully removed
- */
- public final boolean removeNode(final Node<N> node) {
- if (this.containsNode(node)) {
- // Remove the edges (node,target) with key node in successors, and key target in predecessors
- for (final Edge<N, E> successor : this.successors.get(node)) {
- if (successor.getTarget().compareTo(node) != 0) {
- for (final Edge<N, E> predecessor : this.predecessors.get(successor.getTarget())) {
- if (predecessor.getSource().compareTo(node) == 0) {
- this.predecessors.get(successor.getTarget()).remove(predecessor);
- }
- }
- }
- this.successors.remove(node);
- }
- // Remove the edges (source,node) with key node in predecessors, and key source in successors
- for (final Edge<N, E> predecessor : this.predecessors.get(node)) {
- if (predecessor.getSource().compareTo(node) != 0) {
- for (final Edge<N, E> successor : this.successors.get(predecessor.getSource())) {
- if (successor.getTarget().compareTo(node) == 0) {
- this.successors.get(predecessor.getSource()).remove(successor);
- }
- }
- }
- this.predecessors.remove(node);
- }
- // Remove node
- this.nodes.remove(node);
- return true;
- }
- return false;
- }
- /**
- * Removes the specified set of nodes from this component.
- *
- * @param nodes set of nodes
- *
- * @return true if all nodes were removed
- */
- public final boolean removeNodes(final Set<Node<N>> nodes) {
- boolean all = true;
- for (final Node<N> node : nodes) {
- if (!this.removeNode(node)) {
- all = false;
- }
- }
- return all;
- }
- /**
- * Checks if there exists an edge between the two specified nodes.
- *
- * @param source the node origine of the edge
- * @param target the node destination of the edge
- *
- * @return true if the edge is contained by this component
- */
- public final boolean containsEdge(final Node<N> source, final Node<N> target) {
- return this.containsNode(source)
- && this.containsNode(target)
- && this.getSuccessorNodes(source).contains(target)
- && this.getPredecessorNodes(target).contains(source);
- }
- /**
- * Checks if the specified edge belong to this component.
- *
- * @param edge the edge to be checked
- *
- * @return true if the edge is contained by this component
- */
- public final boolean containsEdge(final Edge<N, E> edge) {
- return this.containsEdge(edge.getSource(), edge.getTarget());
- }
- /**
- * Adds an edge between the specified nodes to this component: `to` is added
- * as a successor of `source`.
- *
- * If the case where specified nodes don't belongs to the node set, then the
- * edge will not be added.
- *
- * @param source the node origin of the edge
- * @param target the node destination of the edge
- * @param content the edge content
- *
- * @return true if the edge was successfully added
- */
- public final boolean addEdge(final Node<N> source, final Node<N> target, final Object content) {
- if (this.containsNode(source) && this.containsNode(target)) {
- final Edge<N, E> edge = new Edge(source, target, content);
- this.successors.get(source).add(edge);
- this.predecessors.get(target).add(edge);
- return true;
- }
- return false;
- }
- /**
- * Adds an edge between the specified nodes to this component: `to` is added
- * as a successor of `source`.
- *
- * If the case where specified nodes don't belongs to the node set, then the
- * edge will not be added.
- *
- * @param source the node origin of the edge
- * @param target the node destination of the edge
- *
- * @return true if the edge was successfully added
- */
- public final boolean addEdge(final Node<N> source, final Node<N> target) {
- return this.addEdge(source, target, null);
- }
- /**
- * Adds the specified edge to this component in the successors of
- * edge.getSource() and in the predecessors of edge.getTarget().
- *
- * If the case where nodes to and source of this edges don't belongs to the
- * node set, then the edge will not be added.
- *
- * @param edge the edge to be added
- *
- * @return true if the edge was added
- */
- public final boolean addEdge(final Edge<N, E> edge) {
- if (this.containsNode(edge.getSource()) && this.containsNode(edge.getTarget())) {
- this.successors.get(edge.getSource()).add(edge);
- this.predecessors.get(edge.getTarget()).add(edge);
- return true;
- }
- return false;
- }
- /**
- * Removes source this component the edge between the specified node.
- *
- * `to` is removed source the successors of `source` and `to` is removed
- * source
- * the predecessors of `source`.
- *
- * @param source the node origine of the edge
- * @param target the node destination of the edge
- *
- * @return true if the edge was removed
- */
- public final boolean removeEdge(final Node<N> source, final Node<N> target) {
- if (this.containsEdge(source, target)) {
- final Edge<N, E> edge = new Edge(source, target);
- this.successors.get(source).remove(edge);
- this.predecessors.get(target).remove(edge);
- return true;
- }
- return false;
- }
- /**
- * Removes source this component the specified edge source the successors of
- * edge.getSource() and source the predecessors of edge.getTarget().
- *
- * @param edge the edge to be removed.
- *
- * @return true if the edge was removed
- */
- public final boolean removeEdge(final Edge<N, E> edge) {
- if (this.containsEdge(edge)) {
- this.successors.get(edge.getSource()).remove(edge);
- this.predecessors.get(edge.getTarget()).remove(edge);
- return true;
- }
- return false;
- }
- /*
- * --------------- ACYCLIC CHECKING METHODS ------------
- */
- /**
- * Returns the subgraph of this component induced by the specified set of
- * nodes.
- *
- * The subgraph only contains nodes of the specified set that also are in
- * this component.
- *
- * @param nodes The set of nodes
- *
- * @return The subgraph
- *
- * @todo implement a SubGraph class?
- */
- public ConcreteDGraph<N, E> getSubgraphByNodes(final Set<Node<N>> nodes) {
- ConcreteDGraph<N, E> graph = new ConcreteDGraph<N, E>();
- // addition of nodes in the subgraph
- for (Node<N> node : nodes) {
- if (this.containsNode(node)) {
- graph.addNode(node);
- }
- }
- // addition of edges in the subgraph
- for (Edge<N, E> edge : this.getEdges()) {
- if (graph.containsNode(edge.getTarget())) {
- graph.addEdge(edge);
- }
- }
- return graph;
- }
- /**
- * Returns the subgraph of this component induced by the specified set of
- * edges.
- *
- * The subgraph contains all nodes of this components, and only edges of the
- * specified set that also are in this component.
- *
- * @param edges The set of edges
- *
- * @return The subgraph
- *
- * @todo implement a SubGraph class?
- */
- public ConcreteDGraph<N, E> getSubgraphByEdges(final Set<Edge<N, E>> edges) {
- ConcreteDGraph<N, E> graph = new ConcreteDGraph<N, E>();
- // addition of all nodes in the subgraph
- for (Node<N> node : this.nodes) {
- graph.addNode(node);
- }
- // addition of specified edges in the subgraph
- for (Edge<N, E> edge : edges) {
- if (this.containsEdge(edge)) {
- graph.addEdge(edge);
- }
- }
- return graph;
- }
- /**
- * Replaces this component by its complementary graph.
- *
- * There is an edge between to nodes in the complementary graph when there
- * is no edges between the nodes in this component.
- */
- public void complementary() {
- for (Node<N> source : this.nodes) {
- TreeSet<Node<N>> newSuccessors = new TreeSet<Node<N>>(this.nodes);
- newSuccessors.removeAll(this.getSuccessorNodes(source));
- TreeSet<Node<N>> oldSuccessors = new TreeSet<Node<N>>(this.getSuccessorNodes(source));
- for (Node<N> target : oldSuccessors) {
- this.removeEdge(source, target);
- }
- for (Node<N> target : newSuccessors) {
- this.addEdge(source, target);
- }
- }
- }
- /*
- * --------------- GRAPH TREATMENT METHODS ------------
- */
- /**
- * Computes the reflexive reduction of this component.
- *
- * @return the number of removed edges
- */
- public final int reflexiveReduction() {
- int size = 0;
- for (final Node<N> node : this.nodes) {
- if (this.containsEdge(node, node)) {
- size++;
- this.removeEdge(node, node);
- }
- }
- return size;
- }
- /**
- * Computes the reflexive closure of this component.
- *
- * @return the number of added edges
- */
- public final int reflexiveClosure() {
- int size = 0;
- for (final Node<N> node : this.nodes) {
- if (!this.containsEdge(node, node)) {
- size++;
- this.addEdge(node, node);
- }
- }
- return size;
- }
- /**
- * Computes the transitive closure of this component.
- *
- * This treatment is performed in $O(nm+m_c)$, where $n$ corresponds to the
- * number of nodes, $m$ to the number of edges, and $m_c$ to the number of edges
- * in the closure. This treatment improves the Roy-Warshall algorithm that
- * directly implements the definition in $O(log(m) n^3)$.
- *
- * This treatment is overridden in class {@link DAGraph} with a more
- * efficient algorithm dedicated to directed acyclic graph.
- *
- * @return the number of added edges
- */
- public int transitiveClosure() {
- int size = 0;
- // mark each node to false
- final TreeMap<Node<N>, Boolean> mark = new TreeMap<Node<N>, Boolean>();
- for (final Node<N> node : this.nodes) {
- mark.put(node, Boolean.FALSE);
- }
- // treatment of nodes
- final List<Node<N>> list = new ArrayList<Node<N>>();
- for (final Node<N> source : this.nodes) {
- list.clear();
- list.add(source);
- while (!list.isEmpty()) {
- // Remove the first node
- final Node<N> source2 = list.remove(0);
- for (final Node<N> target : this.getSuccessorNodes(source2)) {
- // treatment of target when not marked
- if (!mark.get(target)) {
- mark.put(target, Boolean.TRUE);
- this.addEdge(source, target);
- list.add(target);
- size++;
- }
- }
- }
- for (final Node<N> target : this.getSuccessorNodes(source)) {
- mark.put(target, Boolean.FALSE);
- }
- }
- return size;
- }
- /**
- * Transposes this component by replacing for each node its successor set by
- * its predecessor set, and its predecessor set by its successor set.
- */
- public final void transpose() {
- ConcreteDGraph<N, E> tmp = new ConcreteDGraph<N, E>(this);
- for (Edge<N, E> edge : tmp.getEdges()) {
- this.removeEdge(edge);
- this.addEdge(new Edge(edge.getTarget(), edge.getSource(), edge.getContent()));
- }
- }
- /**
- * Returns the directed acyclic graph where each node corresponds to a
- * strongly connected component (SCC) of this component stored in a TreeSet
- * of nodes.
- *
- * When two nodes in two different SCC are in relation, the same is for the
- * SCC they belongs to.
- *
- * @return The directed acyclic graph
- */
- public DAGraph<SortedSet<Node<N>>, Object> getStronglyConnectedComponent() {
- DAGraph<SortedSet<Node<N>>, Object> cc = new DAGraph<SortedSet<Node<N>>, Object>();
- // first depth first search
- ConcreteDGraph<N, E> tmp = new ConcreteDGraph<N, E>(this);
- tmp.transitiveClosure();
- ArrayList<Node<N>> last = tmp.depthFirstSearch()[1];
- // transposition of the graph
- ConcreteDGraph<N, E> transposedGraph = new ConcreteDGraph<N, E>(this);
- transposedGraph.transpose();
- // sort nodes according to the reverse last sort
- ArrayList<Node<N>> sort = new ArrayList<Node<N>>();
- Object[] array = last.toArray();
- for (int i = array.length - 1; i >= 0; i--) {
- sort.add((Node<N>) array[i]);
- }
- // second depth first search according to sort
- TreeSet<Node<N>> visited = new TreeSet<Node<N>>();
- for (Node<N> node : sort) {
- if (!visited.contains(node)) {
- last = transposedGraph.depthFirstSearch(node, visited, sort)[1];
- visited.addAll(last);
- TreeSet<Node<N>> sCC = new TreeSet<Node<N>>(last);
- // a strongly connected component is generated
- cc.addNode(new Node<SortedSet<Node<N>>>(sCC)); // addition of
- }
- }
- // edges between strongly connected component
- for (Node<SortedSet<Node<N>>> ccSource : cc.getNodes()) {
- for (Node<SortedSet<Node<N>>> ccTarget : cc.getNodes()) {
- for (Node<N> source : ccSource.getContent()) {
- for (Node<N> target : ccTarget.getContent()) {
- if (tmp.getSuccessorNodes(source).contains(target)) {
- cc.addEdge(ccSource, ccTarget);
- }
- }
- }
- }
- }
- cc.reflexiveReduction();
- return cc;
- }
- /**
- * Set the set of nodes of this component.
- *
- * @param nodes The nodes
- *
- * @return this for chaining
- */
- protected ConcreteDGraph<N, E> setNodes(final TreeSet<Node<N>> nodes) {
- this.nodes = nodes;
- return this;
- }
- /**
- * Returns the successors of this component.
- *
- * @return the map
- */
- protected TreeMap<Node<N>, TreeSet<Edge<N, E>>> getSuccessors() {
- return this.successors;
- }
- /**
- * Set the successors of this component.
- *
- * @param successors The successors
- *
- * @return this for chaining
- */
- protected ConcreteDGraph<N, E> setSuccessors(final TreeMap<Node<N>, TreeSet<Edge<N, E>>> successors) {
- this.successors = successors;
- return this;
- }
- /**
- * Returns the predecessors of this component.
- *
- * @return the map
- */
- protected TreeMap<Node<N>, TreeSet<Edge<N, E>>> getPredecessors() {
- return this.predecessors;
- }
- /**
- * Set the predecessors of this component.
- *
- * @param predecessors The predecessors
- *
- * @return this for chaining
- */
- protected ConcreteDGraph<N, E> setPredecessors(final TreeMap<Node<N>, TreeSet<Edge<N, E>>> predecessors) {
- this.predecessors = predecessors;
- return this;
- }
- /**
- * Returns a two cells array containing the first visited sort on the nodes,
- * and the last visited sort on the nodes, by a depth first traverse issued
- * source the specified node.
- *
- * @param source The source node
- * @param visited The visited nodes
- * @param sort The sort parameter
- *
- * @return The array
- *
- * @todo Do we change that to iterators? Change to private and add a method
- * that return an iterator
- */
- private ArrayList<Node<N>>[] depthFirstSearch(Node<N> source, TreeSet<Node<N>> visited, ArrayList<Node<N>> sort) {
- ArrayList<Node<N>> first = new ArrayList<Node<N>>();
- ArrayList<Node<N>> last = new ArrayList<Node<N>>();
- first.add(source);
- visited.add(source);
- ArrayList<Node<N>>[] arrayVisited = new ArrayList[2];
- if (sort != null) {
- // search according to a sort
- for (Node<N> node : sort) {
- if (this.getSuccessorNodes(source).contains(node) && !visited.contains(node)) {
- arrayVisited = this.depthFirstSearch(node, visited, sort);
- visited.addAll(arrayVisited[0]);
- first.addAll(arrayVisited[0]);
- last.addAll(arrayVisited[1]);
- }
- }
- } else {
- // classical search
- for (Node<N> node : this.getSuccessorNodes(source)) {
- if (!visited.contains(node)) {
- arrayVisited = this.depthFirstSearch(node, visited, sort);
- visited.addAll(arrayVisited[0]);
- first.addAll(arrayVisited[0]);
- last.addAll(arrayVisited[1]);
- }
- }
- }
- last.add(source);
- arrayVisited[0] = first;
- arrayVisited[1] = last;
- return arrayVisited;
- }
- /**
- * Returns a two cells array containing the first visited sort on the nodes,
- * and the last visited sort on the nodes, by a depth first search.
- *
- * @return The array
- */
- private ArrayList<Node<N>>[] depthFirstSearch() {
- TreeSet<Node<N>> visited = new TreeSet<Node<N>>();
- ArrayList<Node<N>>[] arrayVisited = new ArrayList[2];
- ArrayList<Node<N>> first = new ArrayList<Node<N>>();
- ArrayList<Node<N>> last = new ArrayList<Node<N>>();
- for (Node<N> node : this.nodes) {
- if (!visited.contains(node)) {
- arrayVisited = this.depthFirstSearch(node, visited, null);
- visited.addAll(arrayVisited[0]);
- first.addAll(arrayVisited[0]);
- last.addAll(arrayVisited[1]);
- }
- }
- arrayVisited[0] = first;
- arrayVisited[1] = last;
- return arrayVisited;
- }
- /**
- * This class implements a sorted set of the edges.
- *
- * @param <N> Node content type
- * @param <E> Edge content type
- */
- private class Edges<N, E> extends AbstractSet<Edge<N, E>> implements SortedSet<Edge<N, E>> {
- /**
- * The underlying graph.
- */
- private final ConcreteDGraph<N, E> graph;
- /**
- * Constructs a sorted set of the edges source a graph.
- *
- * @param graph A ConcreteDGraph
- */
- Edges(final ConcreteDGraph<N, E> graph) {
- this.graph = graph;
- }
- /**
- * Get the underlying graph.
- *
- * @return the graph
- */
- protected final ConcreteDGraph<N, E> getGraph() {
- return this.graph;
- }
- /**
- * Implements the SortedSet interface.
- *
- * @return the first edge
- */
- public final Edge<N, E> first() {
- throw new UnsupportedOperationException();
- }
- /**
- * Implements the SortedSet interface.
- *
- * @return the last edge
- */
- public final Edge<N, E> last() {
- throw new UnsupportedOperationException();
- }
- /**
- * Implements the SortedSet interface.
- *
- * @param edge the to edge
- *
- * @return The head set
- *
- * @throws UnsupportedOperationException
- */
- public final SortedSet<Edge<N, E>> headSet(final Edge<N, E> edge) {
- throw new UnsupportedOperationException();
- }
- /**
- * Implements the SortedSet interface.
- *
- * @param edge the source edge
- *
- * @return The tail set
- *
- * @throws UnsupportedOperationException
- */
- public final SortedSet<Edge<N, E>> tailSet(final Edge<N, E> edge) {
- throw new UnsupportedOperationException();
- }
- /**
- * Implements the SortedSet interface.
- *
- * @param fromEdge the source edge
- * @param toEdge the to edge
- *
- * @return The sub set
- *
- * @throws UnsupportedOperationException
- */
- public final SortedSet<Edge<N, E>> subSet(final Edge<N, E> fromEdge, final Edge<N, E> toEdge) {
- throw new UnsupportedOperationException();
- }
- /**
- * Implements the SortedSet interface.
- *
- * @return null
- */
- public final Comparator<? super Edge<N, E>> comparator() {
- return null;
- }
- /**
- * Implements the AbstractCollection class.
- *
- * @return the size of the collection
- */
- public final int size() {
- return this.graph.sizeEdges();
- }
- /**
- * Implements the AbstractCollection class.
- *
- * @return a new edges iterator
- */
- public final EdgesIterator iterator() {
- return new EdgesIterator(this);
- }
- /**
- * This class implements an iterator over the edges of a graph.
- */
- private class EdgesIterator implements Iterator<Edge<N, E>> {
- /**
- * The nodes iterator.
- */
- private final Iterator<Node<N>> nodesIterator;
- /**
- * The edges iterator for the current node.
- */
- private Iterator<Edge<N, E>> edgesIterator;
- /**
- * The edges object.
- */
- private final Edges<N, E> edges;
- /**
- * The hasNext flag.
- */
- private boolean hasNext;
- /**
- * Constructs the iterator source a set of edges.
- *
- * @param edges The edges.
- */
- EdgesIterator(final Edges<N, E> edges) {
- this.edges = edges;
- this.nodesIterator = edges.graph.nodes.iterator();
- this.prepareNext();
- }
- /**
- * Prepare the next edge and the hasNext flag.
- */
- private void prepareNext() {
- this.hasNext = false;
- while (!this.hasNext && this.nodesIterator.hasNext()) {
- this.edgesIterator = this.edges.getGraph().successors.get(this.nodesIterator.next()).iterator();
- this.hasNext = this.edgesIterator.hasNext();
- }
- }
- /**
- * The remove operation is not supported.
- *
- * @throws UnsupportedOperationException
- */
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- /**
- * The next method returns the next edge.
- *
- * @return The next edge
- */
- public Edge<N, E> next() {
- Edge<N, E> edge = this.edgesIterator.next();
- if (!this.edgesIterator.hasNext()) {
- this.prepareNext();
- }
- return edge;
- }
- /**
- * The hasNext method return true if the iterator has a next edge.
- *
- * @return true if the iterator has a next edge
- */
- public boolean hasNext() {
- return this.hasNext;
- }
- }
- }
- }