【JAVA】数据结构之带权图的最小生成树

本文介绍了如何计算无向图的带权最小生成树。在添加边时,只有当终点不在树中或者已在队列但未加入树时,才会考虑与新边进行比较。算法通过优先级队列处理边的权值,并不断更新以找到最小权值的边。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 * 无向图的带权图最小生成树
 * 
 * 如果终点已经在树中,则不能添加边
 * 当终点在队列中但是不在树中时才能与新添加的边比较
 * 
 * mstw():先判断三个条件,三个条件都不满足就将边putInQ,
 * 放进去之后,再从队列中弹出一个权值最小的边边,将末尾的结
 * 点作为下一个起始结点,打印弹出的边边的起始顶点来表示边边。
 * 
 * putInQ():如果队列中已经存在了与要放进去的边边的终点相同
 * 的边边,把要放进队列的边边与已经放进去的边边的权值进行比较。
 * 将终点输入进Q.find()进行查找,返回索引值,然后根据索引值
 * 找到oldDist,与newDist进行比较。
 * 
 * 优先级队列的插入操作不熟悉!!!!!!!!!!!!!!!!!!!!!!!!!
 */ 

package graph;
/*
 * 无向图的带权图最小生成树
 * 
 * 如果终点已经在树中,则不能添加边
 * 当终点在队列中但是不在树中时才能与新添加的边比较
 * 
 * mstw():先判断三个条件,三个条件都不满足就将边putInQ,
 * 放进去之后,再从队列中弹出一个权值最小的边边,将末尾的结
 * 点作为下一个起始结点,打印弹出的边边的起始顶点来表示边边。
 * 
 * putInQ():如果队列中已经存在了与要放进去的边边的终点相同
 * 的边边,把要放进队列的边边与已经放进去的边边的权值进行比较。
 * 将终点输入进Q.find()进行查找,返回索引值,然后根据索引值
 * 找到oldDist,与newDist进行比较。
 * 
 * 优先级队列的插入操作不熟悉!!!!!!!!!!!!!!!!!!!!!!!!!
 */
class Edge{
	int startVert;
	int destVert;
	int distance;
	
	public Edge(int sv, int dv, int d) {
		startVert = sv;
		destVert = dv;
		distance = d;
	}
}

class PriorityQ{
	int MAX_SIZE;
	Edge[] prioQueue;
	int nitems;
	
	public PriorityQ(int size) {
		MAX_SIZE = size;
		prioQueue = new Edge[MAX_SIZE];
		nitems = 0;
	}
	
	public int find(int dest) {
		for(int i=0; i<nitems; i++) {
			if(prioQueue[i].destVert == dest) {
				return i;
			}
		}
		
		return -1;
	}
	//优先级队列的插入
	public void insert(Edge e) {
		int j;
		
		if(nitems == 0) {
			prioQueue[nitems] = e;
		}
		//j--
		for(j=nitems-1; j>=0; j--) {
			if(e.distance > prioQueue[j].distance) {
				prioQueue[j+1] = prioQueue[j];
			}else
			{
				break;
			}	
		}
		prioQueue[j+1] = e;
		nitems++;
	}
	
	public Edge remove() {
		return prioQueue[--nitems];
	}
	
    //有新的权值的话,删除旧的权值
	public void removeN(int n) {
		for(int i=n; i<nitems; i++) {
			prioQueue[i] = prioQueue[i+1];
		}
		nitems--;
	}
	
	public Edge peekMin() {
		return prioQueue[nitems-1];
	}
	
    //获取旧的权值的时候,方便访问
	public Edge peekN(int n) {
		return prioQueue[n];
	}
	
	public boolean isEmpty() {
		return nitems == 0;
	}
	
	public boolean isFull() {
		return nitems == MAX_SIZE;
	}	
	
	public int size() {
		return nitems;
	}
}

class vert{
	char label;
	boolean isInTree;
	
	public vert(char lab) {
		label = lab;
		isInTree = false;
	}
}

public class mstwGraph {
	int MAX_SIZE;
	vert[] VertList;
	int nVerts;
	int INF = 10000;
	int[][] adjMat;
	int size = 15;
	PriorityQ Q;
	
	public mstwGraph(int size) {
		MAX_SIZE = size;
		VertList = new vert[MAX_SIZE];
		nVerts = 0;
		size = 15;
		Q= new PriorityQ(size);

		adjMat = new int[MAX_SIZE][MAX_SIZE];
		for(int i=0; i<MAX_SIZE; i++) {
			for(int j=0; j<MAX_SIZE; j++) {
				adjMat[i][j] = INF;
			}
		}
	}
	
	public void addVerts(char lab) {
		vert v = new vert(lab);
		VertList[nVerts++] = v;
	}
	
	public void addEdge(int startVert, int destVert, int distance) {
		adjMat[startVert][destVert] = distance;
		adjMat[destVert][startVert] = distance;
	}
	
	public void mstw() {
		int currentVert = 0;
		int nInTrees = 1;
		
		while(nInTrees < nVerts) {
			VertList[currentVert].isInTree = true;
			nInTrees++;
			for(int i=0; i<nVerts; i++) {
				int distance = adjMat[currentVert][i];
				if(distance == INF) {
					continue;
				}
				
				if(VertList[i].isInTree) {
					continue;
				}
				
				if(i==currentVert) {
					continue;
				}
				putInQ(currentVert, i, distance);
			}
		  if(Q.size() == 0) {
			  System.out.println("The graph is not conneted!");
			  return;
		  }
		  Edge eMin = Q.remove();
		  int srcVert = eMin.startVert;
		  currentVert = eMin.destVert;
		  System.out.print(VertList[srcVert].label);
		  System.out.print(VertList[currentVert].label+" ");
		}
		
		for(int i=0; i<nVerts; i++) {
			VertList[i].isInTree = false;
		}
	}
	
	
	public void putInQ(int curVert, int oldVert, int newDist) {
		int queueIndex = Q.find(oldVert);
		
		if(queueIndex != -1) {
			int oldDist = Q.peekN(queueIndex).distance;
			if(oldDist>newDist) {
				Q.removeN(queueIndex);
				Edge e = new Edge(curVert, oldVert, newDist);
				Q.insert(e);
			}
		}
        //如果既有相同终点,又权值大,就不进行插入操作了
        else
		{
			Edge e = new Edge(curVert, oldVert, newDist);
			Q.insert(e);
		}
	}
	
	public static void main(String[] args) {
		mstwGraph g = new mstwGraph(20);
		g.addVerts('A');
		g.addVerts('B');
		g.addVerts('C');
		g.addVerts('D');
		g.addVerts('E');
		//g.addVerts('F');
		
		g.addEdge(0, 1, 1);
		g.addEdge(0, 2, 2);
		g.addEdge(0, 4, 5);
		g.addEdge(1, 3, 4);
		g.addEdge(2, 3, 3);
		//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();
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值