find the most valuable vertex among all reachable vertices - java

I have a Directed Graph G=(V,E) that each vertex v has two properties:
r indicating the worthiness
m indicating the highest v''s r (where v' is a reachable vertex from v).
I need to find ms for all vertices in O(|V|+|E|) time.
For example,
Initial G
A(r = 1, m = 1) → B(r = 3, m = 3) ← C(r = 2, m = 2)
↓
D(r = 4, m = 4)
has to be
A(r = 1, m = 4) → B(r = 3, m = 3) ← C(r = 2, m = 3)
↓
D(r = 4, m = 4)
I searched SO and found some Here, but one of the answers does not bound in time and another answer is very badly explained. Is there any simpler idea here?

In practice, I would use use the algorithm from Ehsan's answer, but it's not quite O(V+E). If you really need that complexity, then you can do this:
Divide the graph into strongly-connected components using, e.g., Tarjan's algorithm This is O(V+E).
Make a graph of the SCCs. Every node in an SCC is reachable from every other one, so the node for each SCC in the new graph gets the highest r value in the SCC. You can do this in O(V+E) too.
The graph of SCCs is acyclic, so you can do a topological sort. All the popular algorithms for that are O(V+E).
Process the SCC nodes in reverse topological order, calculating each m from neighbors. Because all the edges point from later to earlier nodes, the inputs for each node will be finished by the time you get to it. This is O(V+E) too.
Go through the original graph, setting every node's m to the value for its component in the SCC graph. O(V)

Use following O(E+V*log(V)) algorithm :
- Reverse all directions
- while |V| > 0 do
find max(v) from remaining nodes in V
from that node execute DFS and find all reachable nodes and update their m as max(V)
remove all updated nodes from V
the time-complexity of this algorithm is as your request O(V*log(V)+E)

How to solve the problem?
Reachable vertices in a directed graph
Which vertices can a given vertex visit?
Which vertices can visit the given vertex?
We are dealing with directed graphs. So, we need to find strongly connected components to answer the questions like above efficiently for this problem.
Once we know the strongly connected components, we can deal with the highest worthiness part.
In every strongly connected component, what is the highest worthiness value? Update accordingly.
Both steps are possible with O(V + E). With proper thought process, I believe it should be able to do both the steps in a single pass.
How to find strongly connected components?
Kosaraju's algorithm
Tarjan's algorithm
Path-based strong component algorithm
If you are looking for something simple, go for Kosaraju's algorithm. To me, it is the simplest of the above three.
If you are looking for efficiency, Kosaraju's algorithm takes two depth-first traversals but the other two algorithms accomplish the same within 1 depth-first traversal.
A Space-Efficient Algorithm for Finding Strongly Connected Components mentions that Tarjan’s algorithm required at most v(2 + 5w) bits of storage, where w is the machine’s word size. The improvement mentioned in the paper reduces the space requirements to v(1 + 3w) bits in the worst case.
Implementation:
Apparently, you are looking for some type of implementation.
For the mentioned 3 ways of finding strongly connected components, you can find java implementation here.
There are multiple Path-based strong component algorithms. To my knowledge, Gabow's algorithm is much simpler to understand than Tarjan's algorithm and the latest in path-based strong component algorithms. You can find java implementation for Gabow's algorithm here.

I am adding this answer, although there are correct answers with upvotes before me, only because you tagged java and python. So I will add java implementation now, and if needed the python implementation will follow.
The algorithm
This is a tweak on the classic topological sort:
foreach vertex:
foreach neighbour:
if didn't yet calculate m, calculate.
Take the maximum of yourself and neighbours. Mark yourself as visited, and if asked again for m, return the calculated.
It is implemented at calculateMostValuableVertex.
Time computation complexity
foreach vertex (O(|V|))
2. foreach edge(O(|E|) totally, as it will eventually go over each edge once.):
If not yet computed, compute m.
Please note that foreach vertex, it will be calculated either in stage 1, or 3. not twice, wince it is checked before the calculation.
Therefore the time complexity of this algorithm is O(|V| + |E|)
Assumptions
This solution relies heavily on the fact that HashMap in Java does operations such as add/update in O(1). That is true in average, but if that is not enough, the same idea can be fully implemented only with arrays, which will improve the solution into O(|V|+|E|) in the worst case.
Implementation
Let's first define the basic classes:
Vertex:
import java.util.ArrayList;
class Vertex {
String label;
public int r; // Worthiness
public int m; // Highest worthiness.
Vertex(String label, int r, int m) {
this.label = label;
this.r = r;
this.m = m;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result * r * m
+ ((label == null) ? 0 : label.hashCode());
return result;
}
#Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Vertex other = (Vertex) obj;
boolean labelEquals;
if (label == null) {
labelEquals = other.label == null;
} else {
labelEquals = label.equals(other.label);
}
return labelEquals && r == other.r && m == other.m;
}
#Override
public String toString() {
return "Vertex{" +
"label='" + label + '\'' +
", r=" + r +
", m=" + m +
'}';
}
}
It is important to define the methods equals and hashCode so later on their hash computations will work as expected.
Graph:
class Graph {
private final Map<Vertex, List<Vertex>> adjVertices = new HashMap<>();
private final Map<String, Vertex> nameToVertex = new HashMap<>();
private final List<Vertex> vertices = new ArrayList<>();
void addVertex(String label, int r, int m) {
Vertex vertex = new Vertex(label, r, m);
adjVertices.putIfAbsent(vertex, new ArrayList<>());
nameToVertex.putIfAbsent(label, vertex);
vertices.add(vertex);
}
void addEdge(String label1, String label2) {
adjVertices.get(nameToVertex.get(label1)).add(nameToVertex.get(label2));
}
public void calculateMostValuableVertex() {
Map<Vertex, Boolean> visitedVertices = new HashMap<>();
for (Vertex vertex : vertices) {
visitedVertices.put(vertex, false);
}
for (Vertex vertex : vertices) {
if (visitedVertices.get(vertex)) {
continue;
}
calculateMostValuableVertexInternal(vertex, visitedVertices);
}
}
public void calculateMostValuableVertexInternal(Vertex vertex, Map<Vertex, Boolean> visitedVertices) {
List<Vertex> neighbours = adjVertices.get(vertex);
visitedVertices.put(vertex, true);
int max = vertex.r;
for (Vertex neighbour: neighbours) {
if (visitedVertices.get(neighbour)) {
max = Math.max(max, neighbour.m);
} else {
calculateMostValuableVertexInternal(neighbour, visitedVertices);
max = Math.max(max, neighbour.m);
}
}
vertex.m = max;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
Iterator<Map.Entry<Vertex, List<Vertex>>> iter = adjVertices.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<Vertex, List<Vertex>> entry = iter.next();
sb.append(entry.getKey());
sb.append('=').append('"');
sb.append(entry.getValue());
sb.append('"');
if (iter.hasNext()) {
sb.append(',').append('\n');
}
}
return "Graph{" +
"adjVertices=\n" + sb +
'}';
}
}
Finally, to run the above logic, you can do:
Graph g = new Graph();
g.addVertex("A", 1, 1);
g.addVertex("B", 3, 3);
g.addVertex("C", 2, 2);
g.addVertex("D", 4, 4);
g.addEdge("A", "B");
g.addEdge("C", "B");
g.addEdge("A", "D");
g.calculateMostValuableVertex();
System.out.println(g);
The output of the above is:
Graph{adjVertices=
Vertex{label='A', r=1, m=4}="[Vertex{label='B', r=3, m=3}, Vertex{label='D', r=4, m=4}]",
Vertex{label='D', r=4, m=4}="[]",
Vertex{label='B', r=3, m=3}="[]",
Vertex{label='C', r=2, m=3}="[Vertex{label='B', r=3, m=3}]"}
as expected. It supports graphs with cycles as well. For example the output of:
Graph g = new Graph();
g.addVertex("A", 1, 1);
g.addVertex("B", 3, 3);
g.addVertex("C", 2, 2);
g.addVertex("D", 4, 4);
g.addVertex("E", 5, 5);
g.addVertex("F", 6, 6);
g.addVertex("G", 7, 7);
g.addEdge("A", "B");
g.addEdge("C", "B");
g.addEdge("A", "D");
g.addEdge("A", "E");
g.addEdge("E", "F");
g.addEdge("F", "G");
g.addEdge("G", "A");
g.calculateMostValuableVertex();
System.out.println(g);
is:
Graph{adjVertices=
Vertex{label='A', r=1, m=7}="[Vertex{label='B', r=3, m=3}, Vertex{label='D', r=4, m=4}, Vertex{label='E', r=5, m=7}]",
Vertex{label='B', r=3, m=3}="[]",
Vertex{label='C', r=2, m=3}="[Vertex{label='B', r=3, m=3}]",
Vertex{label='D', r=4, m=4}="[]",
Vertex{label='E', r=5, m=7}="[Vertex{label='F', r=6, m=7}]",
Vertex{label='F', r=6, m=7}="[Vertex{label='G', r=7, m=7}]",
Vertex{label='G', r=7, m=7}="[Vertex{label='A', r=1, m=7}]"}

I implemented my answer from the linked question in Python. The lines that don't reference minreach closely follow Wikipedia's description of Tarjan's SCC algorithm.
import random
def random_graph(n):
return {
i: {random.randrange(n) for j in range(random.randrange(n))} for i in range(n)
}
class SCC:
def __init__(self, graph):
self.graph = graph
self.index = {}
self.lowlink = {}
self.stack = []
self.stackset = set()
self.minreach = {}
self.components = []
def dfs(self, v):
self.lowlink[v] = self.index[v] = len(self.index)
self.stack.append(v)
self.stackset.add(v)
self.minreach[v] = v
for w in self.graph[v]:
if w not in self.index:
self.dfs(w)
self.lowlink[v] = min(self.lowlink[v], self.lowlink[w])
elif w in self.stackset:
self.lowlink[v] = min(self.lowlink[v], self.index[w])
self.minreach[v] = min(self.minreach[v], self.minreach[w])
if self.lowlink[v] == self.index[v]:
component = set()
while True:
w = self.stack.pop()
self.stackset.remove(w)
self.minreach[w] = self.minreach[v]
component.add(w)
if w == v:
break
self.components.append(component)
def scc(self):
for v in self.graph:
if v not in self.index:
self.dfs(v)
return self.components, self.minreach
if __name__ == "__main__":
g = random_graph(6)
print(g)
components, minreach = SCC(g).scc()
print(components)
print(minreach)

Related

Algorithm to compress my Graph (JGraphT) by delete certain edges and vertexes

I have a graph that i want to compress by creating a new graph. So the vertexes are "Topological Nodes" and the edges are different objects but they have the same parent class. Now in the example i want to delete all edges with type b.
The vertices "Topological Nodes" have a Number (1,2,3). Nothing more so very simple.
The edges have a reference to these nodes.
Example:
Graph {
//uncompressed Graph
1 -- 2 [label="a1"];
2 -- 3 [label="b1"];
3 -- 4 [label="b2"];
4 -- 5 [label="b3"];
5 -- 1 [label="a2"];
}
Graph {
//compressed Graph
5 -- 1 [label="a2"];
5 -- 1 [label="a1"];
}
What i have so far is this:
public void compression(Graph<TopologicalNode, IdentifiedObject> unCompressedGraph){
Set<SubGeographicalRegion> networks = datamodel.equipmentProfile.keySet();
for (SubGeographicalRegion subGeographicalRegion : networks) {
Graph<TopologicalNode, IdentifiedObject> compressedGraph = GraphTypeBuilder
.<TopologicalNode, IdentifiedObject>undirected().allowingSelfLoops(true)
.edgeClass(IdentifiedObject.class).buildGraph();
ArrayList<PowerTransformer> powerTransformers = getPTsFromSubnet(subGeographicalRegion);
for(PowerTransformer powerTransformer :powerTransformers) {
for (PowerTransformerEnd powerTransformerEnd : powerTransformer.getEnds()) {
if (unCompressedGraph.vertexSet().stream().filter(r -> r.equals(powerTransformerEnd.getTerminal().getTopologicalNode())).findAny().isPresent()) {
TopologicalNode start = unCompressedGraph.vertexSet().stream().filter(r -> r.equals(powerTransformerEnd.getTerminal().getTopologicalNode())).findAny().get();
compressedGraph.addVertex(start);
ArrayList<TopologicalNode> nodesToBeCompressed = new ArrayList<>();
Iterator<TopologicalNode> iterator = new DepthFirstIterator<>(unCompressedGraph, start);
while (iterator.hasNext()) {
TopologicalNode nextNode = iterator.next();
Set<IdentifiedObject> eqs = unCompressedGraph.edgesOf(nextNode);
//TODO: How to go on?
}
}
}
}
}
}
So i dont really know how to go on and i am new to JGraphT.
It seems you intend to delete an edge by removing it and merging the nodes touched by the edges. You could do this by:
Finding the edge e1 and its both endpoints, say u and v, in the graph.
2a. If there are multiple edges between u an v, then just remove the edge and there's nothing else to do.
2b. If there's only one edge between u and v, we proceed as follows. Create a new vertex w. Vertex w will be the new 'merged' node. Remove edge e1. Connect all edges from u to its neighbors to w. Do the same for v. Remove nodes u and v.
In code, this translates to:
public static void main(String[] args){
//Create a graph
Graph<Integer, String> g =
new Pseudograph<>(SupplierUtil.createIntegerSupplier(1), null, false);
for(int i=0; i<5; i++)
g.addVertex();
g.addEdge(1,2,"a1");
g.addEdge(2,3,"b1");
g.addEdge(3,4,"b2");
g.addEdge(4,5,"b3");
g.addEdge(5,1,"a2");
removeEdge(g,"b1");
removeEdge(g,"b2");
removeEdge(g,"b3");
System.out.println(g);
}
private static void removeEdge(Graph<Integer, String> g, String edge){
if(!g.containsEdge(edge))
throw new RuntimeException(String.format("Cannot delete edge %s because this edge does not exist in the graph!", edge));
Integer u=g.getEdgeSource(edge);
Integer v=g.getEdgeTarget(edge);
//Case 2a: there are multiple edges between vertex u and v
if(g.getAllEdges(u,v).size()>1){
g.removeEdge(edge);
return;
}
//Case 2b: there is only 1 edge between u and v. Delete the edge, and merge nodes u and v into new node w.
g.removeEdge(edge);
Integer w=g.addVertex();
Set<String> edgesOfU = new HashSet<>(g.edgesOf(u));
Set<String> edgesOfV = new HashSet<>(g.edgesOf(v));
//Remove all edges between u and its neighbors and re-add those edges for node w
for(String e : edgesOfU){
Integer neighbor = Graphs.getOppositeVertex(g,e,u);
g.removeEdge(e);
g.addEdge(w,neighbor,e);
}
//Remove all edges between v and its neighbors and re-add those edges for node w
for(String e : edgesOfV){
Integer neighbor = Graphs.getOppositeVertex(g,e,v);
g.removeEdge(e);
g.addEdge(w,neighbor,e);
}
//Nodes u and v have been replaced by w, so we can safely remove u and v
g.removeVertex(u);
g.removeVertex(v);
}
When executing this code we get the desired graph:
([1, 8], [a1={8,1}, a2={8,1}])
Note that, the delete-and-merge operation could produce graphs with multiple edges between the same node, or self-loops, so we need to use a Pseudograph as underlying graph type.

Sorting list of vector clocks (total order)?

I understand that vector clocks only provide a partial order. So you can't directly sort them. For this reason you use a tie-breaker for vectors that are concurrent, resulting in a total order.
However sorting the vector clocks so that every cause comes before every effect in the resulting list doesn't seem to work and I don't entirely get why.
I have extensive tests that show me that comparing two vectors works:
#Override
public int compareTo(VectorClock<K> that) {
var res = 0;
if (this.isAfter(that))
res = 1;
else if (that.isAfter(this))
res = -1;
else
res = this.timestamp.compareTo(that.timestamp);
System.out.println("compare " + this + " : " + that + " => " + res);
return res;
}
public boolean isAfter(VectorClock<K> that) {
boolean anyClockGreater = false;
var set = new HashSet<K>();
set.addAll(this.keySet());
set.addAll(that.keySet());
for (K key : set) {
final Clock thatClock = that.get(key);
final Clock thisClock = this.get(key);
if (thisClock == null || thisClock.isBefore(thatClock)) {
return false;
} else if (thisClock.isAfter(thatClock)) {
anyClockGreater = true;
}
}
// there is at least one local timestamp greater or local vector clock has additional timestamps
return anyClockGreater || that.entrySet().size() < entrySet().size();
}
However when sorting a list of vector clocks, e.g. one with two vectors that have a happenedBefore relationship and a third vector that is concurrent to both others, it may happen that only the concurrent one is compared to the two others, and the vectors that depend on each other are not compared to each other. Instead their order is (wrongly) decided transitively by the tie-breaker:
VectorClock<String> v1 = VectorClock.fromString("{0=23, 1=28, 2=15, 3=23, 4=15, 5=22, 6=14, 7=19}"); // after v3
VectorClock<String> v2 = VectorClock.fromString("{0=11, 1=16, 2=28, 3=17, 4=24, 5=15, 6=10, 7=8}");
VectorClock<String> v3 = VectorClock.fromString("{0=15, 1=19, 2=15, 3=20, 4=15, 5=22, 6=14, 7=19}"); // before v1
var s = new ArrayList<>(List.of(v1, v2, v3));
s.sort(VectorClock::compareTo);
assertTrue(s.indexOf(v3) < s.indexOf(v1));
Prints (and fails):
compare {0=11, 1=16, 2=28, 3=17, 4=24, 5=15, 6=10, 7=8} : {0=23, 1=28, 2=15, 3=23, 4=15, 5=22, 6=14, 7=19} => 1
compare {0=15, 1=19, 2=15, 3=20, 4=15, 5=22, 6=14, 7=19} : {0=11, 1=16, 2=28, 3=17, 4=24, 5=15, 6=10, 7=8} => 1
What is the underlying reason for this? Is this generally impossible or is there an error?

Avoiding ConcurrentModificationException in dijkstra's algorithm

For this program, I read in a excel file that lays out a map of towns, towns adjacent to them, and the distance between them, which looks like:
Bourke Nyngan 200
Brewarrina Walgett 134
Broken Hill Mildura 266
Broken Hill Wilcannia 195
Bungendore Queanbeyan 54
etc.
And that's working great. Everything seems perfect. I'm trying to make a program that if I give it two towns, it returns the shortest possible path between the two.
I can get my program to correctly read in the file, and set up everything, so I know that this issue isn't anything to do with the setup. To the best of my knowledge this part of my program works, as my program can get through it without throwing errors:
//returns the Vertex with the smallest distance from a list of Vertices
public static Vertex minDist(List<Vertex> Q){
int min = 2147483647;
Vertex closest = new Vertex("Closest");
for(Vertex v : Q){
if(v.distance < min){
closest = v;
}
}
return closest;
}
//used to relax (change the distance of a town)
public static void relax(Vertex u, Vertex v, int w){
if(v.distance > u.distance + w){
v.distance = u.distance + w;
v.predecessor = u;
}
}
public static void Dijkstra(Graph G, Vertex s){
Vertex u = new Vertex("not good");
List<Vertex> Q = V;
Vertex v = new Vertex("oh no");
//while Q is not empty:
while(!Q.isEmpty()){
//the vertex in Q that has the smallest distance (at first s with 0, then we relax and that changes things)
u = minDist(Q);
if(u.name.equals("Closest")){
//Q.remove(u);
return;
}
Q.remove(u);
S.add(u);
//for each edge e in u's adjacencyList:
for(Edge e : u.roadList){
if(e != null && !e.finish.name.equals(u.name) ){
v = e.finish;
relax(u,v,w(u,v)); //w(u,v) returns the distance between u and v
}
}
}
System.out.println("Q is null");
}
So I have that, and things look okay to me. I know it's a bit Frankenstein'ed together, but I got it to at least run without errors, because the ConcurrentModificationException gets thrown AFTER this method returns in my main method.
This is where my Dijkstra method gets called in my main method. I never reach the line in my code that prints "SHOULD REACH HERE" because the program throws the ConcurrentModificationException.
//if both towns exist and are unique, find the shortest route between them.
if(isTown(town1,V) && isTown(town2,V) && !town1.equals(town2)){
for(Vertex f : V){
if(f.name.equals(town2)){
destination = f;
}
}
System.out.println("Traveling...");
Graph G = new Graph(V,E);
for(Vertex s : V){
if(s.name.equals(town1)){
//////////////////DIJKSTRA STUFF GOES HERE///////////////////
initialize(G,s);
Dijkstra(G, s);
System.out.println("FINISHED DIJKSTRA");
//Print out the things in the vertex array S with their distances.
for(Vertex b : S){
System.out.println(b.name + " (" + b.distance + ")");
}
///////////////////////////////////////////////
}
}
System.out.println("SHOULD REACH HERE");
}
I have never seen a ConcurrentModificationException, my lab TA has never seen a ConcurrentModificationException, and even my professor has never seen a ConcurrentModificationException. Can I get some help with avoiding this? A person in a higher class said that he has only seen this happening when working with multiple threads, and I don't even know what that really means so I assume my program doesn't do that.
If I run the program with with town1 = Grafton and town2 = Bathurst, then the output should be:
First town: Grafton
Second town: Bathurst
Bathurst (820)
Lithgow (763)
Windsor (672)
Singleton (511)
Muswellbrook (463)
Tamworth (306)
Bendemeer (264)
Uralla (218)
Armidale (195)
Ebor (106)
Grafton
But is instead
First town: Grafton
Second town: Bathurst
Grafton (0)
Glen Innes (158)
Inverell (225)
Warialda (286)
Coffs Harbour (86)
I/O error: java.util.ConcurrentModificationException
You're getting this because you're removing from Q while iterating over it it. See Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

DFS cause stack overflow

I write a simple code about dfs in a data file with 720 thousand vertex pair and find stack overflow. I am not quite sure whether it is caused by large data set or problems of my code. Any ideas is appreciated. Code part is showed below:
private void dfs(Graph G, int v) {
dfsMarked[v] = true;
for (Edge e : G.adj(v)) {
int w = e.other(v);
if (!dfsMarked[w]) {
dfsEdgeTo[w] = v;
dfs(G, w);
}
}
}
720 thousand vertex pairs with a pass spanning a few hundred thousand of them will easily overflow stack on most systems.
You needs to switch to an implementation of DFS that uses your own stack allocated independently of Java stack:
Stack<Integer> stack = new Stack<Integer>();
stack.push(start);
while (!stack.empty()) {
int v = stack.pop();
dfsMarked[v] = true;
for (Edge e : G.adj(v)) {
int w = e.other(v);
if (!dfsMarked[w]) {
dfsEdgeTo[w] = v;
stack.push(w);
}
}
}
Note: The above assumes that adjacency lists are unordered. If you need to preserve the specific ordering to match the recursive version, change the nested loop to enumerate adjacency lists in reverse.

Modification to Dijkstra, verification needed

Dijkstra algorithm has a step which mentions "chose the node with shortest path". I realize that this step is unnecessary if we dont throw a node out of the graph/queue. This works great in my knowledge with no known disadvantage. Here is the code. Please instruct me if it fails ? if it does then how ? [EDIT => THIS CODE IS TESTED AND WORKS WELL, BUT THERE IS A CHANCE MY TEST CASES WERE NOT EXHAUSTIVE, THUS POSTING IT ON STACKOVERFLOW]
public Map<Integer, Integer> findShortest(int source) {
final Map<Integer, Integer> vertexMinDistance = new HashMap<Integer, Integer>();
final Queue<Integer> queue = new LinkedList<Integer>();
queue.add(source);
vertexMinDistance.put(source, 0);
while (!queue.isEmpty()) {
source = queue.poll();
List<Edge> adjlist = graph.getAdj(source);
int sourceDistance = vertexMinDistance.get(source);
for (Edge edge : adjlist) {
int adjVertex = edge.getVertex();
if (vertexMinDistance.containsKey(adjVertex)) {
int vertexDistance = vertexMinDistance.get(adjVertex);
if (vertexDistance > (sourceDistance + edge.getDistance())) {
//previous bug
//vertexMinDistance.put(adjVertex, vertexDistance);
vertexMinDistance.put(adjVertex, sourceDistance + edge.getDistance())
}
} else {
queue.add(adjVertex);
vertexMinDistance.put(adjVertex, edge.getDistance());
}
}
}
return vertexMinDistance;
}
Problem 1
I think there is a bug in the code where it says:
int vertexDistance = vertexMinDistance.get(adjVertex);
if (vertexDistance > (sourceDistance + edge.getDistance())) {
vertexMinDistance.put(adjVertex, vertexDistance);
}
because this has no effect (vertexMinDistance for adjVertex is set back to its original value).
Better would be something like:
int vertexDistance = vertexMinDistance.get(adjVertex);
int newDistance = sourceDistance + edge.getDistance();
if (vertexDistance > newDistance ) {
vertexMinDistance.put(adjVertex, newDistance );
}
Problem 2
You also need to add the adjVertex into the queue using something like:
int vertexDistance = vertexMinDistance.get(adjVertex);
int newDistance = sourceDistance + edge.getDistance();
if (vertexDistance > newDistance ) {
vertexMinDistance.put(adjVertex, newDistance );
queue.add(adjVertex);
}
If you don't do this then you will get an incorrect answer for graphs such as:
A->B (1)
A->C (10)
B->C (1)
B->D (10)
C->D (1)
The correct path is A->B->C->D of weight 3, but without the modification then I believe your algorithm will choose a longer path (as it doesn't reexamine C once it has found a shorter path to it).
High level response
With these modifications I think this approach is basically sound, but you should be careful about the computational complexity.
Dijkstra will only need to go round the main loop V times (where V is the number of vertices in the graph), while your algorithm may need many more loops for certain graphs.
You will still get the correct answer, but it may take longer.
Although the worst-case complexity will be much worse than Dijkstra, I would be interested in how well it performs in practice. My guess is that it will work well for sparse almost tree-like graphs, but less well for dense graphs.

Categories

Resources