2
\$\begingroup\$

I think the part to get shortest path from the cost table got pretty messy. Also can use some tips on how to avoid the extra O(V+E) work checking all edges from source to dest after getting the cost table, or have a better optimized implementation in general.

DirectedGraph.scala

case class Vertex(id: String)
case class Edge(source: Vertex, dest: Vertex, weight: Int)


class DirectedGraph {
  val adjacencyTable: mutable.Map[Vertex, Array[Edge]] = new mutable.HashMap[Vertex, Array[Edge]]()

  def addVertex(vertex: Vertex): Unit = adjacencyTable.put(vertex, new Array[Edge](0))

  def addEdge(source: Vertex, dest: Vertex, weight: Int): Unit =
    adjacencyTable.put(source, adjacencyTable(source) :+ Edge(source, dest, weight))

  def getEdges: Array[Edge] = adjacencyTable.keys.flatMap(i => adjacencyTable(i)).toArray
}

BellmanFord.java

public class BellmanFord {

  private DirectedGraph graph;

  public BellmanFord(DirectedGraph graph) {
    this.graph = graph;
  }

  public List<Vertex> getShortestPath(Vertex source, Vertex dest) {
    Map<Vertex, Integer> costs = getCostMap(source);
    List<Vertex> retList = new ArrayList<>();
    Edge minEdge = null;
    
    retList.add(source);

    if (source == dest) return retList;
    if (graphHasNegativeCycle(costs))
      throw new IllegalStateException("Graph cannot have negative cycles");
    if (costs.get(dest) == Integer.MAX_VALUE)
      throw new IllegalArgumentException("There are no valid paths from source to destination");
    
    for (Edge e : graph.adjacencyTable().get(source).get())
      if (minEdge == null || e.weight() < minEdge.weight())
        minEdge = e;

    retList.addAll(getShortestPath(minEdge.dest(),dest));
    return retList;
  }

  private Map<Vertex, Integer> getCostMap(Vertex source) {
    Map<Vertex, Integer> ret = initCostMap(source);
    for (int i = 0; i < ret.size() - 1; i++) {
      relaxEdges(ret);
    }
    return ret;
  }

  private void relaxEdges(Map<Vertex, Integer> costMap) {
    for (Edge edge : graph.getEdges()) {
      if (costMap.get(edge.source()) + edge.weight() < costMap.get(edge.dest())) {
        costMap.put(edge.dest(), costMap.get(edge.source()) + edge.weight());
      }
    }
  }
  
  private boolean graphHasNegativeCycle(Map<Vertex, Integer> costMap) {
    for (Edge edge : graph.getEdges()) {
      if (costMap.get(edge.source()) + edge.weight() < costMap.get(edge.dest())) {
        return true;
      }
    }
    return false;
  }

  private Map<Vertex, Integer> initCostMap(Vertex source) {
    Map<Vertex, Integer> costMap = new HashMap<>();
    graph.adjacencyTable().foreach(
        kvp -> costMap.put(kvp._1, kvp._1 == source ? 0 : Integer.MAX_VALUE)
    );
    return costMap;
  }
}
\$\endgroup\$
2
  • \$\begingroup\$ Is there a requirement to do one in Scala and the other in Java? \$\endgroup\$ Commented Jul 13, 2020 at 23:45
  • 1
    \$\begingroup\$ Not really, I was just mixing and matching for fun \$\endgroup\$ Commented Jul 13, 2020 at 23:56

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.