/**
* Kürzeste Wege in einem Graphen ermitteln
*
* @author neubauer 03.12.2022 create
*/
public class Dijkstra
{
// grün = leere Menge
// gelb = ausgangselement
// distanz von v = 0
// so lange menge der gelben elemente nicht leer ist
// wähle das element aus den gelben elementen mit der geringsten Entfernung als w
// färbe w grün
// für alle nachfolger von w als wI
// wenn wI nicht gelb oder grün
// färbe die kante rot,
// färbe wI gelb; Distanz von wI ist distanz von w + kosten des übergangs von w zu wI
// sonst wenn wI gelb
// wenn distanz von wI kleiner als distanz von w + kosten des übergangs von w zu wI
// färbe die kante rot,
// färbe die bisher rote kante zu wI gelb
// dist(wI) = dist(w)+cost(w,wI)
// sonst
// färbe w, wI gelb
// sonst
// färbe w, wI gelb
private static final int N = 6;
enum Status
{
GRAY,
RED,
YELLOW,
GREEN;
}
static Node[] graph = new Node[N];
static double[] dist = new double[N];
static Node[] father = new Node[N];
static boolean[] green = new boolean[N];
static class Node
{
private char name;
private NodeLink successorLeft;
private NodeLink successorRight;
private Status status = Status.GRAY;
private int distance;
Node(final char c)
{
this.name = c;
}
public char getName()
{
return name;
}
public void setName(final char name)
{
this.name = name;
}
public NodeLink getSuccessorLeft()
{
return successorLeft;
}
public void setSuccessorLeft(final NodeLink successorLeft)
{
this.successorLeft = successorLeft;
}
public NodeLink getSuccessorRight()
{
return successorRight;
}
public void setSuccessorRight(final NodeLink successorRight)
{
this.successorRight = successorRight;
}
public Status getStatus()
{
return status;
}
public void setStatus(final Status status)
{
this.status = status;
}
public int getDistance()
{
return distance;
}
public void setDistance(final int distance)
{
this.distance = distance;
}
}
static class NodeLink
{
private int targetNodeIndex;
private int cost;
private Status status = Status.GRAY;
NodeLink(final int target, final int cost)
{
this.targetNodeIndex = target;
this.cost = cost;
}
public int getTargetNodeIndex()
{
return targetNodeIndex;
}
public void setTargetNodeIndex(final int targetNodeIndex)
{
this.targetNodeIndex = targetNodeIndex;
}
public int getCost()
{
return cost;
}
public void setCost(final int cost)
{
this.cost = cost;
}
public Status getStatus()
{
return status;
}
public void setStatus(final Status status)
{
this.status = status;
}
}
static class LinkIterator
{
private boolean leftVisited = false;
private boolean rightVisited = false;
private Node node;
LinkIterator(final Node node)
{
this.node = node;
}
public boolean hasNext()
{
return !leftVisited || !rightVisited;
}
public NodeLink getNext()
{
if (!leftVisited)
{
leftVisited = true;
return node.getSuccessorLeft();
}
if (!rightVisited)
{
rightVisited = true;
return node.getSuccessorRight();
}
return null;
}
}
public static void main(final String[] args)
{
initNodes();
dijkstra();
output();
}
private static void output()
{
for (int i = 0; i < graph.length; i++)
{
System.out.println(graph[i].getName() + ": " + graph[i].getDistance());
LinkIterator lit = new LinkIterator(graph[i]);
while (lit.hasNext())
{
NodeLink next = lit.getNext();
if (next != null && next.getStatus() == Status.RED)
{
System.out.println("Link to " + next.getTargetNodeIndex() + " Status " + next.getStatus() + " cost " + next.getCost());
}
}
}
}
private static void dijkstra()
{
Node v = graph[0];
v.setStatus(Status.YELLOW);
v.setDistance(0);
while (hasYellowNodes(graph))
{
Node w = getNearestYellow(graph);
w.setStatus(Status.GREEN);
LinkIterator lit = new LinkIterator(w);
while (lit.hasNext())
{
NodeLink next = lit.getNext();
if (next != null)
{
Node wI = graph[next.getTargetNodeIndex()];
if (wI.getStatus() != Status.YELLOW && wI.getStatus() != Status.GREEN)
{
next.setStatus(Status.RED);
wI.setStatus(Status.YELLOW);
wI.setDistance(w.getDistance() + next.getCost());
}
else if (wI.getStatus() == Status.YELLOW)
{
if ((w.getDistance() + next.getCost()) < wI.getDistance())
{
next.setStatus(Status.RED);
removeRedLink(graph, wI);
wI.setDistance(w.getDistance() + next.getCost());
}
else
{
next.setStatus(Status.YELLOW);
}
}
else
{
next.setStatus(Status.YELLOW);
}
}
}
}
}
private static void removeRedLink(final Node[] graph, final Node wI)
{
boolean removed = false;
for (int i = 0; i < graph.length; i++)
{
LinkIterator lit = new LinkIterator(graph[i]);
while (lit.hasNext())
{
NodeLink candidate = lit.getNext();
if (candidate.getStatus() == Status.RED && graph[candidate.getTargetNodeIndex()].getName() == wI.getName())
{
candidate.setStatus(Status.YELLOW);
removed = true;
break;
}
}
if (removed)
{
break;
}
}
}
private static Node getNearestYellow(final Node[] nodes)
{
Node result = null;
if (hasYellowNodes(nodes))
{
result = nodes[firstYellowNode(nodes)];
for (int i = firstYellowNode(nodes); i < nodes.length; i++)
{
if (nodes[i].getStatus() == Status.YELLOW && nodes[i].getDistance() < result.getDistance())
{
result = nodes[i];
}
}
}
return result;
}
private static boolean hasYellowNodes(final Node[] nodes)
{
boolean result = false;
if (nodes != null && nodes.length > 0)
{
for (int i = 0; i < nodes.length; i++)
{
if (nodes[i].getStatus() == Status.YELLOW)
{
result = true;
break;
}
}
}
return result;
}
private static int firstYellowNode(final Node[] nodes)
{
int result = -1;
if (nodes != null && nodes.length > 0)
{
for (int i = 0; i < nodes.length; i++)
{
if (nodes[i].getStatus() == Status.YELLOW)
{
result = i;
break;
}
}
}
return result;
}
private static void initNodes()
{
char c = 'A';
for (int i = 0; i < N; i++)
{
graph[i] = new Node(c++);
}
// 0 1 2 3 4 5
// A B C D E F
graph[0].setSuccessorLeft(new NodeLink(1, 30));
graph[0].setSuccessorRight(new NodeLink(5, 90));
graph[1].setSuccessorLeft(new NodeLink(2, 10));
graph[1].setSuccessorRight(new NodeLink(3, 40));
graph[2].setSuccessorLeft(new NodeLink(0, 40));
graph[2].setSuccessorRight(new NodeLink(5, 10));
graph[3].setSuccessorLeft(new NodeLink(4, 30));
graph[5].setSuccessorLeft(new NodeLink(4, 20));
}
}