prim算法,加点不构成回路
其实就是n个顶点寻找n-1条边,设集合为A,初始为空,每次加入一个顶点,并保证加入的顶点与集合A中的某个顶点的路径长度是集合A中的点与不在集合中的顶点构成的所有路径中是最小的。
构造2数组:权重数组B和边的另一节点保存数组C,下标都表示节点,长度都为节点个数。权重数组保存对应下标顶点的权重。另一数组保存边的另一个顶点
初始化:任取一个顶点加入集合A,权重数组分别赋值为该顶点到各顶点的边的权重,不可达就赋值为Integer.MAX_VALUE。数组C存放加入顶点的下标。
循环权重数组找出最小的权重的边,记下下标。
将下标表示的顶点加入集合A,用新加入的节点更新最小权重数组,如果新加入的节点到未加入节点的路径更小,就更新权重数组对应的值和数组C中保存新加入节点的下标。
循环n-1次顶点加入集合的过程,就得到MST。
代码:
package nuaa.ds;
public class MSTree {
private CreateGraph g;
private String[] vertexes;//邻接矩阵法所
private int[][] vr; //使用的成员变量
private VertexNode[] vertexNodes;//邻接表所使用的成员变量
/**
* 无向图,G在中间外围一圈按行顺序ABCDEF,F最后连个H
* @param c
*/
public MSTree(CreateGraph c){
this.g = c;
switch(g){
case AdjacencyMatrix://邻接矩阵
this.vertexes = new String[]{"A","B","C","D","E","F","G","H"};
vr = new int[8][8];
int max = Integer.MAX_VALUE;
//arcs都有权重
vr[0] = new int[]{0,13,21,max,max,max,3,max};//好
vr[1] = new int[]{13,0,max,25,max,max,34,max};
vr[2] = new int[]{21,max,0,max,7,max,5,max};
vr[3] = new int[]{max,25,max,0,max,18,38,max};//多
vr[4] = new int[]{max,max,7,max,0,9,15,max};
vr[5] = new int[]{max,max,max,18,9,0,2,4};//浪
vr[6] = new int[]{3,34,5,38,15,2,0,max};
vr[7] = new int[]{max,max,max,max,max,4,max,0};//费
break;
case AdjacencyTable:
vertexNodes = new VertexNode[8];
String[] temp = {"A","B","C","D","E","F","G","H"};
for(int i=0;i<vertexNodes.length;i++){
vertexNodes[i] = new VertexNode(temp[i]);
}
vertexNodes[0].arcNode = new ArcNode(1,13);
vertexNodes[0].arcNode.arcNode = new ArcNode(2,21);
vertexNodes[0].arcNode.arcNode.arcNode = new ArcNode(6,3);
vertexNodes[1].arcNode = new ArcNode(0,13);
vertexNodes[1].arcNode.arcNode = new ArcNode(3,25);
vertexNodes[1].arcNode.arcNode.arcNode = new ArcNode(6,34);
vertexNodes[2].arcNode = new ArcNode(0,21);
vertexNodes[2].arcNode.arcNode = new ArcNode(4,7);
vertexNodes[2].arcNode.arcNode.arcNode = new ArcNode(6,5);
vertexNodes[3].arcNode = new ArcNode(1,25);
vertexNodes[3].arcNode.arcNode = new ArcNode(5,18);
vertexNodes[3].arcNode.arcNode.arcNode = new ArcNode(6,38);
vertexNodes[4].arcNode = new ArcNode(2,7);
vertexNodes[4].arcNode.arcNode = new ArcNode(5,9);
vertexNodes[4].arcNode.arcNode.arcNode = new ArcNode(6,15);
vertexNodes[5].arcNode = new ArcNode(4,9);
vertexNodes[5].arcNode.arcNode = new ArcNode(6,2);
vertexNodes[5].arcNode.arcNode.arcNode = new ArcNode(3,18);
vertexNodes[5].arcNode.arcNode.arcNode.arcNode = new ArcNode(7,4);
vertexNodes[6].arcNode = new ArcNode(0,3);
vertexNodes[6].arcNode.arcNode = new ArcNode(1,34);
vertexNodes[6].arcNode.arcNode.arcNode = new ArcNode(2,5);
vertexNodes[6].arcNode.arcNode.arcNode.arcNode = new ArcNode(3,38);
vertexNodes[6].arcNode.arcNode.arcNode.arcNode.arcNode = new ArcNode(4,15);
vertexNodes[6].arcNode.arcNode.arcNode.arcNode.arcNode.arcNode = new ArcNode(5,2);
vertexNodes[7].arcNode = new ArcNode(5,4);
}
}
//n个点n-1条边形成最小生成树,无环的方法其实就是每次加入一个新顶点,与之前的顶点集合中的
//一个顶点形成最小的权重的一条边
public void getMSTree(){
this.getMSTree(g);
}
private void getMSTree(CreateGraph g){
switch(g){
case AdjacencyMatrix:
mMSTree();
break;
case AdjacencyTable:
tMSTree();
}
}
private void mMSTree(){
int[] nodesIndex = new int[vertexes.length];//数组下标就是表示每个顶点,存放值表示这个
//最小权值边的终点,
int[] weights = new int[vertexes.length];//权重在权重数组里面
boolean[] visited = new boolean[vertexes.length];//下标表示该顶点是否访问过
//初始化,0点进入集合,循环写入第0个顶点到各点的路径长度
weights[0] = 0; //nodesIndex数组
visited[0] = true; //本身就为0所以不用赋值了
for(int i=1;i<vertexes.length;i++){
weights[i] = vr[0][i];
}
int minWeight = Integer.MAX_VALUE;
for(int i=1;i<vertexes.length;i++){//循环n-1次,加入顶点形成最小生成树
int index = 0;
for(int j=1;j<weights.length;j++){//循环找到最小的权重边
if(weights[j]<minWeight&&weights[j]!=0&&!visited[j]){
minWeight = weights[j];
index = j;//index就是新加入的节点下标
}
}
visited[index] = true;//这个节点已经进入集合了
minWeight = Integer.MAX_VALUE;//清空上次得到的最小权值
for(int j=0;j<weights.length;j++){
if(!visited[j]&&vr[index][j]<weights[j]&&vr[index][j]!=0){
weights[j] = vr[index][j];
nodesIndex[j] = index;
}
}
}
for(int i=0;i<vertexes.length;i++){
System.out.print(vertexes[i]+"---"+vertexes[nodesIndex[i]]+" ");
}
}
private void tMSTree(){
int[] nodesIndex = new int[vertexNodes.length];//数组下标就是表示每个顶点,存放值表示这个
//最小权值边的终点,默认为0无需初始化
int[] weights = new int[vertexNodes.length];//下标表示顶点,值为边的权重
boolean[] visited = new boolean[vertexNodes.length];//下标表示该顶点是否访问过
visited[0] = true;
//初始化
for(int i=1;i<weights.length;i++){
weights[i] = Integer.MAX_VALUE;
}
ArcNode p = vertexNodes[0].arcNode;
while(p!=null){
weights[p.serialNumber] = p.weight;
p = p.arcNode;
}
int minWeight = Integer.MAX_VALUE;
int index = 0;
for(int k=1;k<nodesIndex.length;k++){//还有n-1个需要加入
for(int i=0;i<weights.length;i++){//循环找出最小权重边
if(!visited[i]&&minWeight>weights[i]){
minWeight = weights[i];
index = i;
}
}
visited[index] = true;//加入这个节点
minWeight = Integer.MAX_VALUE;//清空
//更新权重表
ArcNode q = vertexNodes[index].arcNode;
while(q!=null){
if(!visited[q.serialNumber]&&q.weight<weights[q.serialNumber]){
weights[q.serialNumber] = q.weight;
nodesIndex[q.serialNumber] = index;
}
q = q.arcNode;
}
}
//循环打印MST
for(int i=0;i<vertexNodes.length;i++){
System.out.print(vertexNodes[i].vertex+"---"+
vertexNodes[nodesIndex[i]].vertex+" ");
}
}
class VertexNode{
String vertex;
ArcNode arcNode;
public VertexNode(String vertex){
this.vertex = vertex;
}
}
class ArcNode{
int serialNumber;//存放边连着的节点在vertexNode数组里面的位置
int weight;//权重在求最小生成树时用到,拓扑排序没有
ArcNode arcNode;
public ArcNode(int serialNumber,int weight){
this.serialNumber = serialNumber;
this.weight = weight;
}
}
}