com.microsoft.azure.arm.dag.Graph Maven / Gradle / Ivy
Show all versions of azure-arm-client-runtime Show documentation
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/
package com.microsoft.azure.arm.dag;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* Type representing a directed graph data structure.
*
* Each node in a graph is represented by {@link Node}
*
* @param the type of the data stored in the graph's nodes
* @param the type of the nodes in the graph
*/
public class Graph> {
/**
* the nodes in the graph.
*/
protected Map nodeTable;
/**
* to track the already visited node while performing DFS.
*/
private Set visited;
/**
* to generate node entry and exit time while performing DFS.
*/
private Integer time;
/**
* to track the entry time to each node while performing DFS.
*/
private Map entryTime;
/**
* to track the exit time from each node while performing DFS.
*/
private Map exitTime;
/**
* to track the immediate parent node of each node while performing DFS.
*/
private Map parent;
/**
* to track already processed node while performing DFS.
*/
private Set processed;
/**
* Creates a directed graph.
*/
public Graph() {
this.nodeTable = new TreeMap<>();
this.visited = new HashSet<>();
this.time = 0;
this.entryTime = new HashMap<>();
this.exitTime = new HashMap<>();
this.parent = new HashMap<>();
this.processed = new HashSet<>();
}
/**
* @return all nodes in the graph.
*/
public Collection getNodes() {
return nodeTable.values();
}
/**
* Adds a node to this graph.
*
* @param node the node
*/
public void addNode(NodeT node) {
node.setOwner(this);
nodeTable.put(node.key(), node);
}
/**
* Perform DFS visit in this graph.
*
* The directed graph will be traversed in DFS order and the visitor will be notified as
* search explores each node and edge.
*
* @param visitor the graph visitor
*/
public void visit(Visitor visitor) {
for (Map.Entry item : nodeTable.entrySet()) {
if (!visited.contains(item.getKey())) {
this.dfs(visitor, item.getValue());
}
}
visited.clear();
time = 0;
entryTime.clear();
exitTime.clear();
parent.clear();
processed.clear();
}
private void dfs(Visitor visitor, Node node) {
visitor.visitNode(node);
String fromKey = node.key();
visited.add(fromKey);
time++;
entryTime.put(fromKey, time);
for (String toKey : node.children()) {
if (!visited.contains(toKey)) {
parent.put(toKey, fromKey);
visitor.visitEdge(fromKey, toKey, edgeType(fromKey, toKey));
this.dfs(visitor, this.nodeTable.get(toKey));
} else {
visitor.visitEdge(fromKey, toKey, edgeType(fromKey, toKey));
}
}
time++;
exitTime.put(fromKey, time);
processed.add(fromKey);
}
private EdgeType edgeType(String fromKey, String toKey) {
if (parent.containsKey(toKey) && parent.get(toKey).equals(fromKey)) {
return EdgeType.TREE;
}
if (visited.contains(toKey) && !processed.contains(toKey)) {
return EdgeType.BACK;
}
if (processed.contains(toKey) && entryTime.containsKey(toKey) && entryTime.containsKey(fromKey)) {
if (entryTime.get(toKey) > entryTime.get(fromKey)) {
return EdgeType.FORWARD;
}
if (entryTime.get(toKey) < entryTime.get(fromKey)) {
return EdgeType.CROSS;
}
}
throw new IllegalStateException("Internal Error: Unable to locate the edge type {" + fromKey + ", " + toKey + "}");
}
/**
* Find the path.
*
* @param start key of first node in the path
* @param end key of last node in the path
* @return string containing the nodes keys in the path separated by arrow symbol
*/
protected String findPath(String start, String end) {
if (start.equals(end)) {
return start;
} else {
return findPath(start, parent.get(end)) + " -> " + end;
}
}
/**
* The edge types in a graph.
*/
enum EdgeType {
/**
* An edge (u, v) is a tree edge if v is visited the first time.
*/
TREE,
/**
* An edge (u, v) is a forward edge if v is descendant of u.
*/
FORWARD,
/**
* An edge (u, v) is a back edge if v is ancestor of u.
*/
BACK,
/**
* An edge (u, v) is a cross edge if v is neither ancestor or descendant of u.
*/
CROSS
}
/**
* Represents a visitor to be implemented by the consumer who want to visit the
* graph's nodes in DFS order by calling visit method.
*
* @param the type of the node
*/
interface Visitor {
/**
* visit a node.
*
* @param node the node to visited
*/
void visitNode(U node);
/**
* visit an edge.
*
* @param fromKey key of the from node
* @param toKey key of the to node
* @param edgeType the edge type
*/
void visitEdge(String fromKey, String toKey, EdgeType edgeType);
}
}