最小生成树的两种算法(Prim算法

对于图G,假设集合V是所有顶点的集合,集合E存放最小生成树所有边。现在要实现最小生成树,将实现过程中用到的顶点放入集合U。

从所有未使用的顶点v∈(V-U),和已用的顶点u∈U的边中选取权值最小的边(u,v)。将v放入U,(u,v)放入集合E。如此不断重复。当存储最小生成树

经过的顶点集合U和原顶点集合V相等时,就构造完毕。



如果prim算法是基于邻接矩阵实现的


package lc;

import java.io.IOException;
import java.util.Scanner;

public class MatrixUDG {
	private char[] mVexes;
	private int[][] mMatrix;
	private static final int INF = Integer.MAX_VALUE;
	
	public MatrixUDG(){
		System.out.println("Please input vertex number:");
		int vlen = readInt();
		System.out.println("Please input edge number:");
		int elen = readInt();
		if(vlen<1 || elen<1 || elen>(vlen-1)*vlen){
			System.out.printf("input error:invalid parameters!\n");
			return;
		}
		
		mVexes = new char[vlen];
		for(int i = 0;i<mVexes.length;i++){
			System.out.printf("vertex(%d)",i);
			mVexes[i] = readChar();
		}
		
		mMatrix = new int[vlen][vlen];
		for(int i = 0;i<vlen;i++){
			for(int j = 0;j<vlen;j++){
				if(i == j)
					mMatrix[i][j] = 0;
				else
					mMatrix[i][j] = INF;
			}
		}
		
		for(int i = 0;i<elen;i++){
			System.out.printf("edge(%d):",i);
			char c1 = readChar();
			char c2 = readChar();
			int weight = readInt();
			
			int p1 = getPosition(c1);
			int p2 = getPosition(c2);
			
			if(p1 == -1 || p2 == -1){
				System.out.printf("input error: invalid edge!\n");
				return;
			}
			mMatrix[p1][p2] = weight;
			mMatrix[p2][p1] = weight;
		}
	}
	
	
	public MatrixUDG(char[] Vexes,int[][] Matrix){
		int vlen = Vexes.length;
		mVexes = new char[vlen];
		for(int i = 0;i<mVexes.length;i++){
			mVexes[i] = Vexes[i];
		}
		
		mMatrix = new int[vlen][vlen];
		for(int i = 0;i<vlen;i++){
			for(int j = 0;j<vlen;j++){
				mMatrix[i][j] = Matrix[i][j];
			}
		}
	}
	
	private int getPosition(char ch){
		for(int i = 0;i<mVexes.length;i++){
			if(mVexes[i] == ch)
				return i;
		}
		return -1;
	}
	
	private char readChar(){
		char ch = '0';
		do{
			try{
				ch = (char) System.in.read();
			}catch(IOException e){
				e.printStackTrace();
			}
		}while(!((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')));
		
		return ch;
	}
	
	private int readInt(){
		Scanner scanner = new Scanner(System.in);
		return scanner.nextInt();
	}
	
	//返回顶点v的第一个邻接顶点索引
	private int firstVertex(int v){
		if(v<0 || v>(mVexes.length-1)){
			return -1;
		}
		
		for(int i = 0;i<mVexes.length;i++){
			if(mMatrix[v][i] != 0 && mMatrix[v][i] != INF){
				//当找邻接顶点时,如果既不是自身顶点,也不是没有边的时候
				return i;
			}
		}
		return -1;
	}
	
	//返回顶点v相对于w的下一个邻接顶点的索引,失败就返回-1
	private int nextVertex(int v,int w){
		if(v < 0 || v > (mMatrix.length-1) || w< 0 || w>(mMatrix.length-1))
			return -1;
		for(int i = w + 1;i<mVexes.length;i++){
			if(mMatrix[v][i] != 0 && mMatrix[v][i] != INF)
				return i;
		}
		
		return -1;
	}
	
	private void dfs(int i,boolean[] visited){
		visited[i] = true;
		System.out.printf("%c ",mVexes[i]);
		for(int w = firstVertex(i);w>=0;w = nextVertex(i,w)){
			if(!visited[w])
				dfs(w,visited);
		}
	}
	
	public void dfs(){
		boolean[] visited = new boolean[mVexes.length];
		for(int i = 0;i<mVexes.length;i++){
			visited[i] = false;
		}
		
		System.out.printf("dfs: ");
		for(int i = 0;i<mVexes.length;i++){
			if(!visited[i])
				dfs(i,visited);
		}
		System.out.printf("\n");
	}
	
	public void print(){
		System.out.printf("Matrix Graph:\n");
		for(int i = 0;i<mVexes.length;i++){
			for(int j = 0;j<mVexes.length;j++){
				System.out.printf("%10d",mMatrix[i][j]);
			}
		}
		System.out.printf("\n");
	}
	
    public void prim(int start) {
    	int num = mVexes.length;
    	int index = 0;
    	char[] prims = new char[num];
    	int[] weights = new int[num];
    	
    	prims[index++] = mVexes[start];//原mVexes中以start为最小生成树的起点,则start位置所在的char是prim数组的第一个char值
    	
    	for(int i = 0;i<num;i++){
    		weights[i] = mMatrix[start][i];
    	}//将每个顶点的权值初始化为第start个顶点到该顶点的权值。
    	
    	weights[start] = 0;
    	
    	for(int i = 0;i<num;i++){
    		if(start == i)
    			continue;
    		int j = 0;
    		int k = 0;
    		int min = INF;
    		//在未加入prim最小生成树的顶点集合中,选择当前顶点到未加入顶点中权值最小的边
    		while(j<num){
    			if(weights[j] != 0 && weights[j]<min){
    				min = weights[j];
    				k = j;
    			}
    			j++;
    		}
    		
    		prims[index++] = mVexes[k];//这时prim里新加入的顶点是原mVexes中的顶点k
    		weights[k] = 0;
    		
    		//当第k个顶点被加入到最小生成树的prims数组之后,更新其他顶点的权值。
    		for(j = 0;j<num;j++){
    			if(weights[j] != 0 && mMatrix[k][j] < weights[j]){
    				weights[j] = mMatrix[k][j];
    			}
    		}
    	}
    	
    	//计算最小生成树的权值
		int sum = 0;
		for(int i = 1;i<index;i++){
			int min = INF;
			
			//获取prims[i]在mMatrix中的位置
			int n = getPosition(prims[i]);
			
			
			for(int j = 0;j<i;j++){
				int m = getPosition(prims[j]);
				if(mMatrix[m][n]<min)
					min = mMatrix[m][n];
			}
			sum+=min;
		}
    	
		System.out.printf("PRIM(%c)=%d ",mVexes[start],sum);
		for(int i = 0;i<index;i++){
			System.out.printf("%c " ,prims[i]);
		}
		System.out.printf("\n");//以上是打印prim最小生成树
    }



    public static void main(String[] args) {

        char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

        int matrix[][] = {

                 /*A*//*B*//*C*//*D*//*E*//*F*//*G*/

          /*A*/ {   0,  12, INF, INF, INF,  16,  14},

          /*B*/ {  12,   0,  10, INF, INF,   7, INF},

          /*C*/ { INF,  10,   0,   3,   5,   6, INF},

          /*D*/ { INF, INF,   3,   0,   4, INF, INF},

          /*E*/ { INF, INF,   5,   4,   0,   2,   8},

          /*F*/ {  16,   7,   6, INF,   2,   0,   9},

          /*G*/ {  14, INF, INF, INF,   8,   9,   0}};

        MatrixUDG pG;



        // 自定义"图"(输入矩阵队列)

        //pG = new MatrixUDG();

        // 采用已有的"图"

        pG = new MatrixUDG(vexs, matrix);



        //pG.print();   // 打印图

        //pG.DFS();     // 深度优先遍历

        //pG.BFS();     // 广度优先遍历

        pG.prim(0);   // prim算法生成最小生成树

    }
}
其中深度优先遍历部分也可以改成广度优先遍历

	public void bfs(){
		int head = 0;
		int rear = 0;
		int[] queue = new int[mVexes.length];
		boolean[] visited = new boolean[mVexes.length];
		
		for(int i = 0;i<mVexes.length;i++){
			visited[i] = false;
		}
		
		System.out.printf("BFS: ");
		
		for(int i = 0;i<mVexes.length;i++){
			if(!visited[i]){
				visited[i] = true;
				System.out.printf("%c ",mVexes[i]);
				queue[rear++] = i;
			}
		
		
		while(head != rear){
			int j = queue[head++];//出队列
			for(int k = firstVertex(j);k>=0;k = nextVertex(j,k)){
				if(!visited[k]){
					visited[k] = true;
					System.out.printf("%c ",mVexes[k]);
					queue[rear++] = k;
				}
			}
		}
	}
		System.out.printf("\n");
}



猜你喜欢

转载自blog.csdn.net/Serenity0614/article/details/78733513
今日推荐