算法设计:Prim算法从顶点开始着手。

从一个顶点开始,然后放入到树的集合中,然后重复做如下事情:

    (1)、找最新的顶点到其他顶点的所有边,这些顶点不能在树的集合中,把这些放入优先级队列。

    (2)、找到权值最小的边把它和它所到达的顶点放入树的集合中。

重复上述操作直到所有的顶点都在树中,程序结束。

图论-带权图的最小生成树(Prim)算法_i++

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


输出结果:AD AB BE EC CF