您的位置:首页 > 其它

带权图的最小生成树问题

2017-04-21 15:30 141 查看

带权图的最小生成树问题

假设共有六个定点,分别为命名为0-5,如下图所示:



根据图构建出邻接矩阵adjMat[][]如下(其中权值为-1表示该两点之间没有路径):

adjMat[][]012345
0-16-14-1-1
16-11077-1
2-110-1856
3-178-112-1
4-1-112-1-17
5-1-1-1-17-1

分析

优先级队列以数组的方式来实现,并且数组中,权值越大的值数组下标越小。

首先从任意节点开始,这里从0节点开始,通过搜索邻接矩阵找到0节点到所有相连接点的边:

1、以当前节点号为行遍历该行所有的列,其中列不能等于行号(行号等于列号时代表自身与自身相连)。

2、当该行上某一列的值部不为-1时,代表该点与行值点相连,该值为连线的权值。该案例中邻接矩阵adjMat[0][1]和adjMat[0][3]两个元素不为-1。

3、将该边放在优先级队列中。本案例中队列中有边0-1(6)、0-3(4)。

4、得到优先级队列中的队首元素(即队列中权值最小的元素)并将该边从队列中删除,这里为边0-3。

5、以该边的终点作为新的顶点,这里即边0-3中3为新的顶点。重复以上五个步骤。

注意并不是要把搜索的到邻接矩阵中所有非-1边都放入队列中的,必须符合以下条件的才能进入队列:

1、边的的起点和终点不能是同一个。

2、边的终点已经在树中。

3、边的权值不为-1。

代码的实现

程序主要有四个类构成

1、顶点类Vertex

顶点类具有两个属性,顶点的名字和改点是否已经在树中

class Vertex {
public char label;
public boolean isInTree;

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


2、边类Edge

边类包含三个属性,分别时起点srcVert、终点destVert、边的权重这里用distance表示。

class Edge {
//    starting edge
public int srcVert;
//    ending edge
public int destVert;
public int distance;

public Edge(int srcVert, int destVert, int distance) {
this.srcVert = srcVert;
this.destVert = destVert;
this.distance = distance;
}
}


3、优先级队列类PriorityQ

优先级队列采用数组queArray实现,实现方法比较简单但不严谨,比如队列只能朝一个方向插入,抽取。因此打算专门写一篇文章讨论队列的实现,这里不做重点讨论。并且优先级队列还可以用堆来实现。

队列中用size来标示队列中的元素个数。

队列中包含insert()、removeMin()、peekMin()、peekN()、find()等方法。

insert()用来队列的插入,将权值小的放在队列的首部,即放在数组下标较大的位置;

removeMin()是移除队队首元素即分析部分中所描述的步骤4;

peekMin()用来查看队首元素;

peekN()用来查看队列中下表为n的元素;

find()用来查找边的终点是否已经包含在队列中。

class PriorityQ {
private final int SIZE = 20;
private Edge[] queArray;
private int size;

public PriorityQ() {
queArray = new Edge[SIZE];
size = 0;
}

public void insert(Edge item) {
int j;
for (j = 0; j < size; j++) {
if (item.distance >= queArray[j].distance) {
break;
}
}
for (int k = size - 1; k >= j; k--) {
queArray[k+1] = queArray[k];
}
queArray[j] = item;
size++;
}

public Edge removeMin() {
return queArray[--size];
}

public void removeN(int n) {
for (int j = n; j < size - 1; j++) {
queArray[j] = queArray[j + 1];
}
size--;
}

public Edge peekMin() {
return queArray[size--];
}

public int size() {
return size;
}

public boolean isEmpty() {
return (size == 0);
}

public Edge peekN(int n) {
return queArray
;
}

public int find(int findDex) {
for (int j = 0; j < size; j++) {
if (queArray[j].destVert == findDex) {
return j;
}
}
return -1;
}
}


4、图类Graph

图类中包含邻接矩阵adjMat[][]、顶点数组列表vertexList[]、优先级队列thePQ等,包含mstw()和putInPQ()两个重要的方法

mstw()是实现最小生成树的核心代码:

从顶点0开始搜索,当树中的元素个数和顶点的个数相同时while循环结束算法退出。

按照分析中所述的方法,一次遍历每一行的每一个值,当遇到符合条件的边时调用putInPQ()方法进行队列插入;

然后从优先级队列中取出队收的边元素,以改变元素的终点作为新的顶点,进行下一步。

putInPQ()时队列执行插入的方法

要插入的边的终点不在队列中是,表示这是一个新的节点,因此直接将该边插入队列中,当该边的终点已经在队列中时,查找出队列中到达该终点的旧边,查看旧边的权值,如果旧边的权值比新边的权值大那么将旧的边删除,将新的边插入,否者新的边不再插入队列。解释为如果又发现了一条到达节点的新路径,如果新路径权值比原来的路径权值要小那么就采用新的路径,否者沿用旧的路径。

class Graph {
private final int MAX_VERTS = 8;
private final int INIFITY = -1;
private Vertex[] vertexList;
private int adjMat[][];
private int nVerts;
private int currentVert;
private PriorityQ thePQ;
private int nTree;

public Graph() {
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] = INIFITY;
}
}
thePQ = new PriorityQ();
}

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

public void displayVertex(int v) {
System.out.println(vertexList[v].label);
}

public void mstw() {
currentVert = 0;
while (nTree < nVerts - 1) {
vertexList[currentVert].isInTree = true;
nTree++;
for (int j = 0; j < nVerts; j++) {
if (j == currentVert) {
continue;
}
if (vertexList[j].isInTree) {
continue;
}
int distance = adjMat[currentVert][j];
if (distance == INIFITY) {
continue;
}
putInPQ(j, distance);
}
if (thePQ.size() == 0) {
System.out.println("GRAPH NOT CONNECTED");
return;
}
Edge theEdge = thePQ.removeMin();
int sourceVert = theEdge.srcVert;
currentVert = theEdge.destVert;
System.out.print(vertexList[sourceVert].label);
System.out.print(vertexList[currentVert].label);
System.out.print(" ");

}
for (int i = 0; i < nVerts; i++) {
vertexList[i].isInTree = false;
}
}

public void putInPQ(int newVert, int newDist) {
int queueIndex = thePQ.find(newVert);
if (queueIndex != -1) {
Edge tempEdge = thePQ.peekN(queueIndex);
int oldDist = tempEdge.distance;
if (oldDist > newDist) {
thePQ.removeN(queueIndex);
Edge theEdge = new Edge(currentVert, newVert, newDist);
thePQ.insert(theEdge);
}
} else {
Edge theEdge = new Edge(currentVert, newVert, newDist);
thePQ.insert(theEdge);
}
}
}


程序测试:

public class MSTWApp {
public static void main(String[] args) {
Graph theGraph = new Graph();
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.println("Minimum spanning tree : ");
theGraph.mstw();
System.out.println();
}
}


结果为:

Minimum spanning tree :
AD AB BE EC CF
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: