Prim的Java算法实现

时间:2018-08-13 09:39:24

标签: java data-structures graph minimum-spanning-tree prims-algorithm

我正在尝试使用Java图形HashMap + LinkedList和一个Edge类(包含连接的顶点和权重)来实现Java的Prim算法。

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

我的想法是,从给定的顶点开始: 1)将所有顶点保存到LinkedList中,以便每次访问时都可以将其删除 2)将路径保存到另一个LinkedList中,以便我可以完成最终的MST 3)使用PriorityQueue查找MIN权重

最后,我需要MST,边缘数量和总重量。 我对如何返回MST感到非常困惑,我的代码中几乎没有错误,我不知道如何解决这些错误!

首先,我得到此错误:

    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

问题似乎出在我的getVertices()方法(返回图的所有顶点)中,因为它返回了Set<T>;我试图使用addAll将所有内容放入LinkedList中,并获得此LinkedList的返回值,但它给了我同样的错误。我在做什么错了?

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();
        }
    }

第二个错误是:

   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

我可以通过将Edge<T>强制转换为source来修复它,但是我认为这毫无意义,因为我的想法是我给出一个可以包含任何类型的顶点,而不仅仅是Edges

罪恶的:

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??>;
    }
}

正如我之前所说,我不知道是否应该以MST(可能是我作为输入提供的那张图,删除了最昂贵的边)作为MST返回图,还是将路径最小的LinkedList称为path。 我也不知道如何在MST中找到边的数量。我应该为每个顶点(我的HashMap的keySet)找到LinkedList的大小(即它的值)并将它们相加吗?

编辑:getAdjacentVertices方法

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;
    }
}

1 个答案:

答案 0 :(得分:2)

1)我想错误不是在getVertices()中,而是在Graph而非Edge<T>上将您的T定义为通用的事实。 Graph<T>实例化为Graph<Edge<T1>>,因此将Set<T>作为返回值的实例化为Set<Edge<T1>>

我建议您将Graph定义为Graph<Edge<T>>,然后从那里重构图的逻辑,或者将IEdge<T>定义为Edge<T>的超接口,然后将图重新定义为{{1 }}。

例如(被蒙住眼睛):

Graph<? extends IEdge<T>>

2)1的变体。在这种情况下,您返回的是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()); ,但是由于骑自行车的原因是:

List<T>

在提供for (Edge<T> edge : graph.getAdjacentVertices(source)) 时,getAdjacentVertices的返回值应为Enumerable<Edge<T>>。您可能想在您的Enumerable<T>实现中返回这样的内容:

getAdjacentVertices