图4---无向图得到最小生成树

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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值