老师的代码中对于循环结束的情况是当堆中不为空的时候
我的实现:
优化了时间复杂度? 变成了O((V-1)logE), 这个时间复杂度对吗?如果对的话不就是比O(ElogV)还快了吗?毕竟边的个数是一定大于等于顶点的个数的
public class Prim {
private Graph graph; // 要获取最小生成树的图
private PriorityQueue<Edge> minHeap; // 最小堆, 优先队列, Java自带的优先队列是最小堆实现的
private ArrayList<Edge> minSpanningTree; // 最小生成树的所有边
private boolean[] visited; // 顶点是否已经访问过
public Prim (Graph<? extends Comparable<?>> graph) {
this.graph = graph;
this.minHeap = new PriorityQueue<Edge>();
this.minSpanningTree = new ArrayList<Edge>();
this.visited = new boolean[graph.getPeak()];
for (int i = 0; i < visited.length; i++) {
visited[i] = false;
}
generateMinSpanningTree();
}
private void generateMinSpanningTree () {
// 从树的原顶点开始出发查找
int index = 0;
// 当所有顶点都被遍历之后, 最小生成树也就找到了, 边的数量应该是顶点的数量减一
while (minSpanningTree.size() < graph.getPeak() - 1) {
// 对该顶点进行迭代, 将其所有边都压入最小堆中
Iterators iterator = graph.iterator(index);
while (!iterator.end()) {
Edge next = iterator.next();
// 只将index顶点到一个未访问过的顶点的边压入最小堆
if (!visited[next.getToPeak()]) {
minHeap.add(next);
}
}
// 设置该顶点为已经访问过的, 这样下次其它顶点在迭代的时候就会忽略那些顶点到index的边
visited[index] = true;
// 此时取出最小的边, 如果这个最小边的两个顶点都被访问过了, 那么就提取下一个最小边
// 直到一个被访问一个没被访问则才是横切边, 该边就是最小生成树中的一条边, 并放入最小生成树中
Edge minEdge;
while (true) {
minEdge = minHeap.remove();
if (visited[minEdge.getFromPeak()] && visited[minEdge.getToPeak()]) {
continue;
}
break;
}
minSpanningTree.add(minEdge);
// 将index设置为该最小边中没被访问过的顶点
index = visited[minEdge.getToPeak()] == true ? minEdge.getFromPeak() : minEdge.getToPeak();
}
}
public ArrayList<Edge> getMinSpanningTree () {
return minSpanningTree;
}
}
下面是边的类
public class Edge<T extends Comparable<T>> implements Comparable<Edge<T>>{
// 对于from, to来说, 只有在有向图的时候其意义才会不同
private int from; // 表示边的第一端
private int to; // 表示边的第二端
private T weight; // 边的权重, 用泛型表示, 因为可以是整型, 可以是浮点型
public Edge (int from, int to, T weight) {
this.from = from;
this.to = to;
this.weight = weight;
}
public void setWeight (T weight) {
this.weight = weight;
}
public int getToPeak () {
return to;
}
public int getFromPeak () {
return from;
}
@Override
public String toString () {
return "{from: "+ from + ", to: "+ to + ", weight: " + weight +"}";
}
@Override
public int compareTo(Edge<T> o) {
if (o == null) {
throw new IllegalArgumentException("Edge of o does not exist");
}
return weight.compareTo(o.weight);
}
}