十九、最小生成樹(普里姆算法)


普里姆算法介紹

普里姆(Prim)算法,是用來求加權連通圖的最小生成樹的算法。

基本思想 
對於圖G而言,V是所有頂點的集合;現在,設置兩個新的集合U和T,其中U用於存放G的最小生成樹中的頂點,T存放G的最小生成樹中的邊。 從所有uЄU,vЄ(V-U) (V-U表示出去U的所有頂點)的邊中選取權值最小的邊(u, v),將頂點v加入集合U中,將邊(u, v)加入集合T中,如此不斷重復,直到U=V為止,最小生成樹構造完畢,這時集合T中包含了最小生成樹中的所有邊。

普里姆算法圖解

以上圖G4為例,來對普里姆進行演示(從第一個頂點A開始通過普里姆算法生成最小生成樹)。

初始狀態:V是所有頂點的集合,即V={A,B,C,D,E,F,G};U和T都是空! 
第1步:將頂點A加入到U中。 
    此時,U={A}。 
第2步:將頂點B加入到U中。 
    上一步操作之后,U={A}, V-U={B,C,D,E,F,G};因此,邊(A,B)的權值最小。將頂點B添加到U中;此時,U={A,B}。 
第3步:將頂點F加入到U中。 
    上一步操作之后,U={A,B}, V-U={C,D,E,F,G};因此,邊(B,F)的權值最小。將頂點F添加到U中;此時,U={A,B,F}。 
第4步:將頂點E加入到U中。 
    上一步操作之后,U={A,B,F}, V-U={C,D,E,G};因此,邊(F,E)的權值最小。將頂點E添加到U中;此時,U={A,B,F,E}。 
第5步:將頂點D加入到U中。 
    上一步操作之后,U={A,B,F,E}, V-U={C,D,G};因此,邊(E,D)的權值最小。將頂點D添加到U中;此時,U={A,B,F,E,D}。 
第6步:將頂點C加入到U中。 
    上一步操作之后,U={A,B,F,E,D}, V-U={C,G};因此,邊(D,C)的權值最小。將頂點C添加到U中;此時,U={A,B,F,E,D,C}。 
第7步:將頂點G加入到U中。 
    上一步操作之后,U={A,B,F,E,D,C}, V-U={G};因此,邊(F,G)的權值最小。將頂點G添加到U中;此時,U=V。

此時,最小生成樹構造完成!它包括的頂點依次是:A B F E D C G

 

鄰接矩陣:

class Vertex
{
public char label; public boolean wasVisited; public Vertex(char lab)
{ label
= lab; wasVisited = false; } } class UDGraph
{
private final int MAX_VERTS = 20; private Vertex vertexList[]; private int adjMat[][]; private int nVerts; public UDGraph()
{ vertexList
= new Vertex[MAX_VERTS]; adjMat = new int[MAX_VERTS][MAX_VERTS]; nVerts = 0; for(int i=0;i<MAX_VERTS;i++) for(int j=0;j<MAX_VERTS;j++) //最大值表示剛開始頂點間都不連接 adjMat[i][j] = Integer.MAX_VALUE; } public void addVertex(char lab)
{ vertexList[nVerts
++] = new Vertex(lab); } public void addEdge(int start,int end,int weight)
{ adjMat[start][end]
= weight; adjMat[end][start] = weight;//無向圖 } //最開始以vertexList[v]為最小生成樹的起點 public void Prim(int v)
{
//存放剩余頂點到當前生成樹的最短的一條邊的權值 int lowcost[] = new int[MAX_VERTS]; int k=0; for(int i=0;i<nVerts;i++)
{
//將vertexList數組下標第v個頂點到其它頂點的所有邊當作候選邊 lowcost[i] = adjMat[v][i]; } //將vertexList[v]並入樹中 vertexList[v].wasVisited = true; System.out.println(vertexList[v].label); //選中某個頂點后(這里是v),每次選取剩下頂點中的一個,一共要有nVerts-1個次 for(int i=0;i<nVerts-1;i++)
{
int min = Integer.MAX_VALUE; //選出剩下頂點到生成數的最小邊 for(int j=0;j<nVerts;j++)
{
if(!vertexList[j].wasVisited && lowcost[j]<min)
{ min
= lowcost[j]; k=j; } } vertexList[k].wasVisited = true; System.out.println("----"+lowcost[k]+"----"+vertexList[k].label); //將頂點k並入生成樹,並更新剩下頂點到該生成樹的最小邊 for(int m=0;m<nVerts;m++)
{
//如果剩余頂點到k並入后的生成樹的最小邊小於並入前的生成樹的最小邊 if(!vertexList[m].wasVisited && adjMat[k][m]<lowcost[m]) lowcost[m] = adjMat[k][m]; } } } } public class MatrixUDG_Prim
{
public static void main(String[] args)
{ UDGraph theGraph
= new UDGraph(); theGraph.addVertex('A');// 0 theGraph.addVertex('B');// 1 theGraph.addVertex('C');// 2 theGraph.addVertex('D');// 3 theGraph.addVertex('E');// 4 theGraph.addVertex('F');// 5 theGraph.addEdge(0, 1,1);//AB theGraph.addEdge(0, 2,4);//AC theGraph.addEdge(0, 5,6);//AF theGraph.addEdge(1, 3,8);//BD theGraph.addEdge(1, 4,3);//BE theGraph.addEdge(2, 4,9);//CE theGraph.addEdge(2, 5,5);//CF theGraph.addEdge(3, 4,7);//DE theGraph.addEdge(3, 5,10);//DF theGraph.addEdge(4, 5,2);//EF//從0開始,即頂點A開始 theGraph.Prim(0); } }

 

鄰接表:

import java.util.ArrayList; class Vertex
{
public char label; public boolean wasVisited; public Edge firstEdge; public Vertex(char lab)
{
this.label = lab; this.wasVisited = false; firstEdge = null; } } class Edge
{
public int dest; public int weight; public Edge nextEdge; public Edge(int dest,int weight)
{
this.dest= dest; this.weight = weight; nextEdge = null; } } class UDGraph
{
private final int MAX_VERTS = 20;//圖的最大頂點數 private int nVerts = 0;//當前頂點數 private Vertex vertexList[];//頂點鏈表 public UDGraph()
{ vertexList
= new Vertex[MAX_VERTS]; } public void addVertex(char lab)
{ vertexList[nVerts
++] = new Vertex(lab); } public void addEdge(int start,int end,int weight)
{ Edge startEdge
= new Edge(start,weight); Edge endEdge = new Edge(end,weight); Edge edge2 = vertexList[start].firstEdge; if(edge2==null)
{ vertexList[start].firstEdge
= endEdge; }else
{ while(edge2.nextEdge!=null) edge2 = edge2.nextEdge; edge2.nextEdge = endEdge; } Edge edge3 = vertexList[end].firstEdge; if(edge3==null)
{ vertexList[end].firstEdge
= startEdge; }else
{ while(edge3.nextEdge!=null) edge3 = edge3.nextEdge; edge3.nextEdge = startEdge; } } public void displayVertex(int v)
{ System.out.println(vertexList[v].label); }
//最開始以vertexList[v]為最小生成樹的起點 public void Prim(int v)
{
//存放剩余頂點到當前生成樹的最短的一條邊的權值 int lowcost[] = new int[MAX_VERTS]; int k=0; //將vertexList數組下標第v個頂點到其它頂點的所有邊當作候選邊 for(int i=0;i<nVerts;i++)
{ lowcost[i]
= getWeight(v, i); } //將vertexList[v]並入樹中 vertexList[v].wasVisited = true; System.out.println(vertexList[v].label); //選中某個頂點后(這里是v),每次選取剩下頂點中的一個,一共要有nVerts-1個次 for(int i=0;i<nVerts-1;i++)
{
int min = Integer.MAX_VALUE; //選出剩下頂點到生成數的最小邊 for(int j=0;j<nVerts;j++)
{
if(!vertexList[j].wasVisited && lowcost[j]<min)
{ min
= lowcost[j]; k=j; } } vertexList[k].wasVisited = true; System.out.println("----"+lowcost[k]+"----"+vertexList[k].label); //將頂點k並入生成樹,並更新剩下頂點到該生成樹的最小邊 for(int m=0;m<nVerts;m++){ //如果剩余頂點到k並入后的生成樹的最小邊小於並入前的生成樹的最小邊 if(!vertexList[m].wasVisited && getWeight(k, m)<lowcost[m]) lowcost[m] = getWeight(k, m); } } } /* * 獲取邊<start, end>的權值;若start和end不是連通的,則返回無窮大。 */ private int getWeight(int start, int end)
{
if (start==end) return 0; Edge currentEdge = vertexList[start].firstEdge; while (currentEdge != null)
{
if (end==currentEdge.dest) return currentEdge.weight; currentEdge = currentEdge.nextEdge; } return Integer.MAX_VALUE; } } public class ListUDG_Prim
{
public static void main(String[] args)
{ UDGraph theGraph
= new UDGraph(); theGraph.addVertex('A'); // 0 theGraph.addVertex('B'); // 1 theGraph.addVertex('C'); // 2 theGraph.addVertex('D'); // 3 theGraph.addVertex('E'); // 4 theGraph.addVertex('F'); // 5 theGraph.addEdge(0, 1,1); //AB theGraph.addEdge(0, 2,4); //AC theGraph.addEdge(0, 5,6); //AF theGraph.addEdge(1, 3,8); //BD theGraph.addEdge(1, 4,3); //BE theGraph.addEdge(2, 4,9); //CE theGraph.addEdge(2, 5,5); //CF theGraph.addEdge(3, 4,7); //DE theGraph.addEdge(3, 5,10);//DF theGraph.addEdge(4, 5,2); //EF//從0開始,即頂點A開始 theGraph.Prim(0); } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM