最小生成树问题

来源:互联网 发布:免费手机拍证件照软件 编辑:程序博客网 时间:2024/06/18 05:17

最小生成树问题,是要用最少的边遍历完所有的顶点的问题。在普通的图中,最小生成树可以通过深度优先搜索和广度优先搜索来取得,用深度优先搜索比较容易,因为它不会两次访问同一个顶点,所以通过深度优先搜索得到的结果必定是最小生成树。

以下是无向图的最小生成树的代码:(具体步骤见笔记本。。)

首先是类Vertex

public class Vertex {
public char label;
public boolean wasvisited;
public Vertex(char label)
{
this.label=label;
wasvisited=false;
}
}

类StackX

深度优先搜索要用到栈

public class StackX {
private int top;//top of the stack
private int[] arr;
private int size;//size of the stack
public StackX(int size){
this.size=size;
arr=new int[size];//create a stack
top=-1;//the stack is empty

}
public void push(int value)//push item on the top of the stack
{
arr[++top]=value;//insert item
}
public void pop()//take item from the top of the stack
{
arr[top--]=0;

}
public int peep()//print out the item on the top of the stack
{
return arr[top];
}
public boolean isEmpty()
{
return (top==-1);
}
}

类Graph

public class Graph {
int maxSize;//size of the array
 Vertex[] vertexList;//array of vertices
 int[][] adjMatrix;//adjacency matrix
 int nverts;//current number of vertices
StackX theStack;
public Graph(int maxSize)//constructor
{
this.maxSize=maxSize;
vertexList=new Vertex[maxSize];
adjMatrix=new int[maxSize][maxSize];
nverts=0;
theStack=new StackX(maxSize);
queue=new Queue(maxSize);

}
public  void addVertex(char label)
{
vertexList[nverts++]=new Vertex(label);
}
public void addEdge(int start,int end)
{
adjMatrix[start][end]=1;
adjMatrix[end][start]=1;
}
public void displayVertex(int v)
{
System.out.print(vertexList[v].label);
}
public int getUnvisitedVertex(int v)//获取没有被访问的点
{
for(int i=0;i<nverts;i++)
{
if(adjMatrix[v][i]==1&&vertexList[i].wasvisited==false)
{
return i;
}
}
return -1;
}
public void MinimumSpanningTree()//最小生成树(DFS)
{
vertexList[0].wasvisited=true;//start at 0,mark it
theStack.push(0);//push it
while(!theStack.isEmpty())//until the stack empty 
{
int currentVertex=theStack.peep();//get the stack top
//get the next unvisited neighbour
int v=getUnvisitedVertex(currentVertex);
if(v==-1)//if  no unvisited neighbour
{
theStack.pop();//pop it away
}
else//if there is
{
vertexList[v].wasvisited=true;//get a neighbour
displayVertex(currentVertex);//display it
displayVertex(v);//display the neighbour
System.out.print(" ");
theStack.push(v);//push it
}
}
//if stack is empty,so we are done.
for(int i=0;i<nverts;i++)//reset the flags
{
vertexList[i].wasvisited=false;
}
}

}
}

主类MSTApp

public class MstApp {


public static void main(String[] args) {
// TODO Auto-generated method stub
Graph theGraph=new Graph(5);
theGraph.addVertex('A');
theGraph.addVertex('B');
theGraph.addVertex('C');
theGraph.addVertex('D');
theGraph.addVertex('E');
theGraph.addEdge(0,1);//AB
theGraph.addEdge(1,2);//BC
theGraph.addEdge(0,3);//AC
theGraph.addEdge(3,4);//CD
theGraph.addEdge(0,2);//AC
theGraph.addEdge(0,4);//AE
theGraph.addEdge(1,3);//BD
theGraph.addEdge(1,4);//BE
theGraph.addEdge(2,4);//CE
theGraph.addEdge(2,3);//CD
System.out.println("Minimum spanning tree:");
theGraph.MinimumSpanningTree();

}

}

上面的程序显示了对a图求最小生成树,并得到b图的结果


输出结果:

Minimum spanning tree:
AB BC CD DE 

求无权图的最小生成树需要O(|v|+|E|)的时间,因为他至少遍历了所有的顶点和走过了所有的边。

   而对于带权图的最小生成树问题,则可以通过一个实例来理解

某国需要铺设电视线路,求造价最低的铺设方案,在边上的数字代表在这两个城市之间铺设线路的费用。

           这时,我们需要用另外的方法来解决这个问题。这次我们用的是优先级队列,以下是算法要点:

1.找到从最新的顶点到其他顶点的线路,这些顶点不能在树的集合中,把这些线路放进优先级队列

  2.从优先级队列中取得造价最低的线路,把它和它所到达的地点放入树的集合中,他所到达的顶点成为新的顶点来重复步骤1。

3.重复以上两个步骤,直到所有地点都在树的集合中。

以下是带权图最小生成树的代码:

代码中并没有一个真正的“树”来存放顶点,而是通过布尔值来判断顶点是否在树中,再通过一个整型来计算树中顶点的数目。

 类Vertex  同样,我们需要Vertex类,而类中的布尔值改为了isInTree,用来判断顶点是否在树的集合中。 

public class Vertex {
public char label;
public boolean isInTree;
public Vertex(char label)
{
this.label=label;
isInTree=false;
}


}

类Edge  Edge类的对象都是图中的边,存放的是起点和终点。但由于该图并不是有向图,起点和终点只是一个标识,并不是严格意义上的起点和终点。

public class Edge {
int start;
int end;
int distance;
public Edge(int start,int end,int distance)
{
this.start=start;
this.end=end;
this.distance=distance;
}
}


类PriorityQ   要注意的是优先级队列中的数组存放的是Edge类型的元素。

public class PriorityQ {
private int maxSize;
private Edge[] queue;
private int nItems;


public PriorityQ(int maxSize)
{
this.maxSize=maxSize;
queue=new Edge[maxSize];
nItems=0;

}
public void insert(Edge item)
{
int i;
if(nItems==0)//if no item
{
queue[nItems++]=item;//insert at 0
}
else
{
for(i=nItems-1;i>=0;i--)
{
if(queue[i].distance<item.distance)//if new item larger
{
queue[i+1]=queue[i];//shift forward
}
else//if smaller
break;//done shifting
}
queue[i+1]=item;
nItems++;
}
}
public Edge removeMin()
{
return(queue[--nItems]);
}
public void removeN(int n)//remove the specific item
{
for(int i=n;i<nItems-1;i++)
{
queue[i]=queue[i+1];
}
nItems--;
}
public Edge peekMin()
{
return(queue[nItems-1]);
}
public Edge peekN(int n)
{
return (queue[n]);
}
public boolean isEmpty()
{
return(nItems==0);
}
public boolean isFull()
{
return(nItems==maxSize);
}
public int find(int end)//find item with specific end
{
for(int j=0;j<nItems;j++)
{
if(queue[j].end==end)
{
return j;
}
}
return -1;

}

}


类WeightGraph 带权图

public class WeightGraph {
int maxSize;//size of the array
 Vertex[] vertexList;//array of vertices
 int[][] adjMatrix;//adjacency matrix
 int nverts;//current number of vertices
 int currentVert;
 PriorityQ thePQ;
 private int nTree;//number of verts in trees
 private final int INFINITY=10000; 
public WeightGraph(int maxSize)//constructor
{
this.maxSize=maxSize;
vertexList=new Vertex[maxSize];
adjMatrix=new int[maxSize][maxSize];
for(int i=0;i<adjMatrix.length;i++)
{
for(int j=0;j<adjMatrix[i].length;j++)
{
adjMatrix[i][j]=INFINITY;
}
}
thePQ=new PriorityQ(maxSize);
nverts=0;

}
public  void addEdge(int start,int end,int weight)
{
adjMatrix[start][end]=weight;
adjMatrix[end][start]=weight;
}
public  void addVertex(char label)
{
vertexList[nverts++]=new Vertex(label);
}


public void displayVertex(int v)
{
System.out.print(vertexList[v].label);
}
public void mstw()
{
currentVert=0;
while(nTree<nverts-1)//while not all verts on the tree
{
vertexList[currentVert].isInTree=true;//put current verts on tree
nTree++;
for(int j=0;j<adjMatrix[currentVert].length;j++)
{
if(j==currentVert)//skip if is the currentVert
{
continue;
}
if(vertexList[j].isInTree==true)//skip if it's in tree
{
continue;
}
int distance=adjMatrix[currentVert][j];
if(distance==INFINITY)//skip if there is no edge
{
continue;

}
PutInPQ(j,distance);
}
if(thePQ.isEmpty())
{
System.out.print("Graph is not connected.");
return;
}
//remove the minimum distance from PQ
Edge theEdge=thePQ.removeMin();
int start=theEdge.start;
currentVert=theEdge.end;
//display it from start to the end
System.out.print(vertexList[start].label);
System.out.print(vertexList[currentVert].label);
System.out.print(" ");
}//end while

}
public void PutInPQ(int newVert,int newDist)
{
//is there another edge with the same destination?
int queueIndex=thePQ.find(newVert);
if(queueIndex!=-1)//get the edge's index
{
Edge tempEdge=thePQ.peekN(queueIndex);//get the
int oldDist=tempEdge.distance;//get the old distance
if(oldDist>newDist)//if the old distance is bigger than the new one
{
thePQ.removeN(queueIndex);//remove the old one
Edge theEdge=new Edge(currentVert,newVert,newDist);//insert the new one
thePQ.insert(theEdge);

}
//else:no action,leave the old vertex there
}//end if
else{//no edge with the same destination
Edge theEdge=new Edge(currentVert,newVert,newDist);//insert the new one
thePQ.insert(theEdge);
}
}//end PutInPQ



}//end the class

最后 是主类

MSTWApp

public class MSTWApp {


public static void main(String[] args) {
WeightGraph theGraph=new WeightGraph(6);
theGraph.addVertex('A');
theGraph.addVertex('B');
theGraph.addVertex('C');
theGraph.addVertex('D');
theGraph.addVertex('E');
theGraph.addVertex('F');
theGraph.addEdge(0, 1, 6);
theGraph.addEdge(0, 3, 4);
theGraph.addEdge(1, 2, 10);
theGraph.addEdge(1, 3, 7);
theGraph.addEdge(1, 4, 7);
theGraph.addEdge(2, 3, 8);
theGraph.addEdge(2, 4, 5);
theGraph.addEdge(2, 5, 6);
theGraph.addEdge(3, 4, 12);
theGraph.addEdge(4, 5, 7);
System.out.print("Minimum Spanning Tree:");
theGraph.mstw();
System.out.println();


}


}

以下是图示结果:


以下是输出结果:

Minimum Spanning Tree:AD AB BE EC CF 

对带权图求最小生成树需要O((V+E)logV)的时间,具体为什么我还不太清楚。。。

0 0
原创粉丝点击