Skip to content

Commit

Permalink
Replaced the old breadth-first and depth-first iterators
Browse files Browse the repository at this point in the history
  • Loading branch information
sbalev committed Sep 2, 2011
1 parent a22a034 commit 70ec71e
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 527 deletions.
255 changes: 50 additions & 205 deletions src/org/graphstream/graph/BreadthFirstIterator.java
@@ -1,230 +1,75 @@
/*
* Copyright 2006 - 2011
* Julien Baudry <julien.baudry@graphstream-project.org>
* Antoine Dutot <antoine.dutot@graphstream-project.org>
* Yoann Pigné <yoann.pigne@graphstream-project.org>
* Guilhelm Savin <guilhelm.savin@graphstream-project.org>
*
* This file is part of GraphStream <http://graphstream-project.org>.
*
* GraphStream is a library whose purpose is to handle static or dynamic
* graph, create them from scratch, file or any source and display them.
*
* This program is free software distributed under the terms of two licenses, the
* CeCILL-C license that fits European law, and the GNU Lesser General Public
* License. You can use, modify and/ or redistribute the software under the terms
* of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
* URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
*/
package org.graphstream.graph;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;

import org.graphstream.graph.Edge;
import org.graphstream.graph.Node;

/**
* Iterator allowing to explore a graph in a breadth-first way.
*
* This iterator also allows to compute the depth or each node (number of edges
* crossed to reach a node from the starting node) as well as the maximum
* depth. Be careful that this depth does not take eventual weights of edges,
* it only counts edges. The depth of each node and the depth max are known
* only when all the nodes have been processed by this iterator (only when
* {@link #hasNext()} returns false).
*
* @complexity O(n+m) with n the number of nodes and m the number of edges.
* @since 20040730
*/
public class BreadthFirstIterator<T extends Node> implements Iterator<T> {
// Attributes

/**
* Respect the edge orientation?.
*/
protected boolean directed = true;

/**
* Already processed nodes.
*/
protected HashMap<T,Integer> closed = new HashMap<T,Integer>();

/**
* Nodes remaining to process. The iteration continues as long as this array
* is not empty.
*/
protected LinkedList<T> open = new LinkedList<T>();

/**
* Maximum depth.
*/
protected int depthMax = 0;

// Constructors

/**
* New breadth-first iterator starting at the given start node.
*
* @param startNode
* The node where the graph exploration begins.
*/
public BreadthFirstIterator(Node startNode) {
this(startNode, true);
}
protected boolean directed;
protected Graph graph;
protected Node[] queue;
protected int[] depth;
protected int qHead, qTail;

/**
* New breadth-first iterator starting at the given start node.
*
* @param startNode
* The node where the graph exploration begins.
* @param directed
* If true the iterator respects the edge direction (the
* default).
*/
@SuppressWarnings("unchecked")
public BreadthFirstIterator(Node startNode, boolean directed) {
open.add((T)startNode);
closed.put((T)startNode,0);
this.directed = directed;
graph = startNode.getGraph();
int n = graph.getNodeCount();
queue = new Node[n];
depth = new int[n];

int s = startNode.getIndex();
for (int i = 0; i < n; i++)
depth[i] = i == s ? 0 : -1;
queue[0] = startNode;
qHead = 0;
qTail = 1;
}

// Accessors

/**
* Is this iterator respecting edge orientation ?.
*
* @return True if edge orientation is respected (the default).
*/
public boolean isDirected() {
return directed;
}

/**
* Depth of the more distant node from the starting point of the BFS, this is also known as
* the eccentricity if the graph non-weighted. This method can only be used reliably after all
* the nodes have been processed.
*
* @return The maximum depth of a node from the starting node (in edge jumps).
*/
public int getDepthMax() {
return depthMax;
}

/**
* Depth of a given node. The depth here is minimal number of edges to cross to reach
* the given node from the starting node of the BFS. Weights are not used.
* This method can only be used reliably after all the nodes
* have been processed, if the depth has not been computed -1 is returned.
*
* @param node
* The node for which the depth is required.
* @return The depth of the given node.
*/
public int getDepthOf(Node node) {
Integer i = closed.get(node);

if(i != null)
return (int)i;

return -1;
}

/**
* Is the given node tabu?.
*
* Tabu nodes are nodes that have already been discovered (and are therefore either
* in closed or open or both).
*
* @param node
* The node to test.
* @return True if tabu.
*/
protected boolean tabu(T node) {
return closed.containsKey(node);
public BreadthFirstIterator(Node startNode) {
this(startNode, true);
}

/**
* Is there a next node to process?.
*
* @return True if it remains nodes.
*/
public boolean hasNext() {
return open.size() > 0;
return qHead < qTail;
}

/**
* Next node to process, in BF order.
*
* @return The next node.
*/
public T next() throws NoSuchElementException {
if (open.size() > 0) {
T next = open.removeFirst();

addNeighborsOf(next);

return next;
} else {
throw new NoSuchElementException("no more elements in iterator");
@SuppressWarnings("unchecked")
public T next() {
if (qHead >= qTail)
throw new NoSuchElementException();
Node current = queue[qHead++];
int level = depth[current.getIndex()] + 1;
Iterable<Edge> edges = directed ? current.getEachLeavingEdge()
: current.getEachEdge();
for (Edge e : edges) {
Node node = e.getOpposite(current);
int j = node.getIndex();
if (depth[j] == -1) {
queue[qTail++] = node;
depth[j] = level;
}
}
return (T)current;
}

/**
* Append the neighbors of the given node (excepted nodes already processed/marked)
* in the list of nodes to process next.
*
* @param node
* The nodes the neighbors are to be processed.
*/
protected void addNeighborsOf(T node) {
Iterator<? extends Edge> k;

if (directed)
k = node.getLeavingEdgeIterator();
else
k = node.getEdgeIterator();
public void remove() {
throw new UnsupportedOperationException(
"This iterator does not support remove");
}

boolean found = false;
int curDepth = ((int)closed.get(node)) + 1;

while (k.hasNext()) {
Edge edge = k.next();
T adj = edge.getOpposite(node);
public int getDepthOf(Node node) {
return depth[node.getIndex()];
}

if (!tabu(adj)) {
open.add(adj);
closed.put(adj, curDepth);
found = true;
}
}

if(found && curDepth > depthMax)
depthMax = curDepth;
public int getDepthMax() {
return depth[queue[qTail - 1].getIndex()];
}

// Commands
public boolean tabu(Node node) {
return depth[node.getIndex()] != -1;
}

/**
* Unsupported with this iterator.
*/
public void remove() throws UnsupportedOperationException,
IllegalStateException {
throw new UnsupportedOperationException(
"cannot remove a node using this iterator (yet)");
public boolean isDirected() {
return directed;
}
}
}
75 changes: 0 additions & 75 deletions src/org/graphstream/graph/BreadthFirstIteratorIndexed.java

This file was deleted.

0 comments on commit 70ec71e

Please sign in to comment.