算法设计:Prim算法从顶点开始着手。
从一个顶点开始,然后放入到树的集合中,然后重复做如下事情:
(1)、找最新的顶点到其他顶点的所有边,这些顶点不能在树的集合中,把这些放入优先级队列。
(2)、找到权值最小的边把它和它所到达的顶点放入树的集合中。
重复上述操作直到所有的顶点都在树中,程序结束。
Graph_mstw.java
package com.mapbar.structure; /** * * Class Graph_mstw.java * * Description 带权图的最小生成树算法 * 总原则:选择从已经处理过的点到未处理过的点的费用最低的边。 * Company mapbar * * author Chenll E-mail: * * Version 1.0 * * Date 2012-10-9 上午11:25:06 */ // 定义边 class Edge { public int srcVert; // 源点 public int destVert; // 目的点 public int distance; // 距离 public Edge(int sv, int dv, int d) { this.srcVert = sv; this.destVert = dv; this.distance = d; } } // 定义节点 class Vertex { public char label; public boolean isInTree; public Vertex(char l) { this.label = l; isInTree = false; } } //定义优先级队列, //找到新的顶点到其它顶点所有边,这些顶点不能在树的集合中,放入优先级队列,找到费用最少的,把它和它所到达的顶点放入树的集合中 class PriorityQ{ private final int SIZE = 20; private Edge[] queArray; private int size; public PriorityQ(){ queArray = new Edge[SIZE]; size = 0; } //新增 public void insert(Edge item){ int j; for(j = 0; j<size; j++){ if(item.distance>=queArray[j].distance){//从大到小排序 break; } } //后移 for(int i = size-1; i>=j; i--){ queArray[i+1] = queArray[i]; } queArray[j] = item; size ++; } //删除最小的 public Edge removeMin(){ return queArray[--size]; } //删除第N个 public void removeN(int n){ //前移 for(int i = n; i<size-1; i++){ queArray[i] = queArray[i+1]; } size --; } public int size(){ return size; } public boolean isEmpty(){ return size == 0; } //获取第N个边 public Edge peekN(int n){ return queArray[n]; } //查找到达指定顶点的边 public int find(int vIndex){ for(int i = 0; i<size; i++){ if(queArray[i].destVert == vIndex){ return i; } } return -1; } } class Graph { private final int MAX_VERTX = 20; // 节点数 private final int INFINITY = 1000000; // 最远距离 private Vertex vertexList[]; private int adjMat[][]; //邻接矩阵 private int nVerts; //记录顶点的个数 private int nTree; //记录树中顶点的个数 private int currentVert; //当前顶点 private PriorityQ thePQ; //优先级队列 public Graph() { vertexList = new Vertex[MAX_VERTX]; adjMat = new int[MAX_VERTX][MAX_VERTX]; nVerts = 0; // 初始化矩阵 for (int i = 0; i < MAX_VERTX; i++) { for (int j = 0; j < MAX_VERTX; j++) { adjMat[i][j] = INFINITY; } } thePQ = new PriorityQ(); } // 添加顶点 public void addVertex(char label) { vertexList[nVerts++] = new Vertex(label); } // 添加边 public void addEdge(int sv, int dv, int dis) { adjMat[sv][dv] = dis; adjMat[dv][sv] = dis; } //最小生成树 public void mstw(){ currentVert = 0; while(nTree < nVerts-1) { vertexList[currentVert].isInTree = true; nTree ++; for(int i = 0; i< nVerts; i++){ //源点和终点相同 if(i == currentVert) continue; //终点已经在树里面 if(vertexList[i].isInTree) continue; //源点和终点没有边 int dis = adjMat[currentVert][i]; if(dis == INFINITY) continue; //加入当前点和终点的边到队列 putInPQ(i, dis); } if(thePQ.size() == 0){ return; } Edge theEdge = thePQ.removeMin(); int sVert = theEdge.srcVert; currentVert = theEdge.destVert; System.out.print(vertexList[sVert].label); System.out.print(vertexList[currentVert].label); System.out.print(" "); } //重新设置 for(int j = 0; j<nVerts; j++){ vertexList[j].isInTree = false; } } public void putInPQ(int vertex,int dis){ int index = thePQ.find(vertex); if(index!=-1){ //检查老边是否有比新边更小的成本,如果新边成本比老边少,需要删除老边,把新边放入 Edge tempEdge = thePQ.peekN(index); int oldDis = tempEdge.distance; if(oldDis > dis){ thePQ.removeN(index); Edge theEdge = new Edge(currentVert,vertex,dis); thePQ.insert(theEdge); } } else { Edge theEdge = new Edge(currentVert,vertex,dis); thePQ.insert(theEdge); } } } public class Graph_mstw { public static void main(String[] args){ Graph g = new Graph(); g.addVertex('A'); g.addVertex('B'); g.addVertex('C'); g.addVertex('D'); g.addVertex('E'); g.addVertex('F'); g.addEdge(0, 1, 6); g.addEdge(0, 3, 4); g.addEdge(1, 2, 10); g.addEdge(1, 3, 7); g.addEdge(1, 4, 7); g.addEdge(2, 3, 8); g.addEdge(2, 4, 5); g.addEdge(2, 5, 6); g.addEdge(3, 4, 12); g.addEdge(4, 5, 7); g.mstw(); } }