javadata-structuresgraphminimum-spanning-treeprims-algorithm

Prim's Algorithm Implementation in Java


I'm trying to implement Prim's Algorithm in Java using for my graph HashMap + LinkedList and a class Edge which contains the connected vertex and the weight:

adjacencyList = new HashMap<T, LinkedList<Edge<T>>>();

My idea was, starting from a given vertex: 1)save all vertices into a LinkedList so I can remove them every time they've been visisted 2)saving the path into another LinkedList so I can have my final MST 3)using a PriorityQueue to find MIN weight

In the end I'll need MST, number of edges and total weight. I'm very confused about how to return MST and I have few errors on my code which I have no idea on how to fix them!

First of all I get this error:

    Prim.java:21: error: no suitable method found for addAll(LinkedList<Edge<T>>)
        unvisited.addAll(graph.getVertices());
                 ^
    method Collection.addAll(Collection<? extends T>) is not applicable
      (argument mismatch; LinkedList<Edge<T>> cannot be converted to Collection<? extends T>)
    method List.addAll(Collection<? extends T>) is not applicable
      (argument mismatch; LinkedList<Edge<T>> cannot be converted to Collection<? extends T>)
    method AbstractCollection.addAll(Collection<? extends T>) is not applicable
      (argument mismatch; LinkedList<Edge<T>> cannot be converted to Collection<? extends T>)
    method LinkedList.addAll(Collection<? extends T>) is not applicable
      (argument mismatch; LinkedList<Edge<T>> cannot be converted to Collection<? extends T>)
  where T is a type-variable: T extends Comparable<T> declared in class Prim

It seems the problem is in my getVertices() method (which return all the vertices of the graph) as it returns a Set<T>; I tried to put everything inside a LinkedList using addAll and get as return this LinkedList but it gives me the same error. What am I doing wrong?

public class Graph<T extends Comparable<T>> {
    .
    .
    public Set<T> getVertices() {
            if (adjacencyList.isEmpty()) {
                System.out.println("Error message.\n");
                return null;
            } else
                return adjacencyList.keySet();
        }
    }

The second error is:

   Prim.java:28: error: incompatible types: T cannot be converted to Edge<T>
            for (Edge<T> edge : graph.getAdjacentVertices(source)) {
                                                          ^
  where T is a type-variable:
    T extends Comparable<T> declared in class Prim
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output

I can fix it by casting Edge<T> to source but I think it doesn't make any sense at all because the idea was that I give a vertex which can contain any type, not only Edges.

Prim's:

public class Prim<T extends Comparable<T>> {
    public <SHOULD I RETURN graph ?> minimumSpanningTree(Graph<Edge<T>> graph, T vertex) {
        //ArgumentException

        double weight = 0;
        T source = vertex;

        LinkedList<T> vertexSet = new LinkedList<>();
        LinkedList<Edge<T>> path = new LinkedList<>();

        vertexSet.addAll(graph.getVertices()); //unvisited ERROR HERE
        vertexSet.remove(source);

        double numberOfVertices = graph.getVertices().size();
        PriorityQueue<Edge<T>> priorityQueue = new PriorityQueue<>();

        while (!vertexSet.isEmpty()) {
            for (Edge<T> edge : graph.getAdjacentVertices(source)) {//ERROR
               if (vertexSet.contains(edge.getDestination())) 
                    priorityQueue.insert(edge);
            }
            Edge<T> minWeight = priorityQueue.extractMin();
            weight += minWeight.getWeight();
            path.add(HERE I SHOULD PUT MST PATH BUT I DON'T KNOW HOW!!);

            source = minWeight.getDestination();
            vertexSet.remove(source);
        }
        return <graph??>;
    }
}

As I said before, I don't know if I should return a graph as MST (maybe the one I give as input deleting the most expensive edges) or the LinkedList called path which saves the path with lowest weight. I also don't know how to find the number of edges in the MST; should I for every vertex (keySet of my HashMap) find the size of the LinkedList (which is its value) and sum them all?

EDIT: getAdjacentVertices method

public LinkedList<T> getAdjacentVertices(T vertex) {
    if (adjacencyList.isEmpty() || adjacencyList.containsKey(vertex) == false) {
        System.out.println("Error msg.\n");
        return null;
    } else {
        LinkedList<T> allAdjacents = new LinkedList<>();
        for (Edge<T> edge : adjacencyList.get(vertex)) {
            allAdjacents.add(edge.getDestination());
        }
        return allAdjacents;
    }
}

Solution

  • 1) I guess the error is not in getVertices() but in the fact that your Graph was defined as generic on Edge<T> and not T. Graph<T> is instantiated as Graph<Edge<T1>>, so Set<T> as return value is istantiated as Set<Edge<T1>>.

    I suggest you define Graph as Graph<Edge<T>>, and refactor the graph's logics from there, or define a IEdge<T> as superinterface of Edge<T> and redefine Graph as Graph<? extends IEdge<T>>.

    For instance (going blindfolded):

    public class Graph<T> {
        Map<T, Edge<T>> adjacencyList;
        public Set<T> getVertices() {
            if (adjacencyList.isEmpty()) {
                System.out.println("Error message.\n");
                return null;
            } else {
                return adjacencyList.keySet();
            }
        }
    }
    
    Graph<Point> p;
    List<Point> points = new LinkedList<>();
    points.addAll(p.getVertices());
    

    2) A variant of 1. In this case, you're returning a List<T> but since you're cycling with:

    for (Edge<T> edge : graph.getAdjacentVertices(source))
    

    the return value of getAdjacentVertices should be an Enumerable<Edge<T>>, while you're providing a Enumerable<T>. You probably want to return something like this in your getAdjacentVertices implementation:

    LinkedList<Edge<T>> allAdjacents = new LinkedList<>();
    for (Edge<T> edge : adjacencyList.get(vertex)) {
        allAdjacents.add(edge);
    }
    return allAdjacents;