带权图的最小生成树问题

来源:互联网 发布:淘宝助理有没有mac版 编辑:程序博客网 时间:2024/05/29 10:38

带权图的最小生成树问题

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

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

adjMat[][] 0 1 2 3 4 5 0 -1 6 -1 4 -1 -1 1 6 -1 10 7 7 -1 2 -1 10 -1 8 5 6 3 -1 7 8 -1 12 -1 4 -1 -1 12 -1 -1 7 5 -1 -1 -1 -1 7 -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[n];    }    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 
1 0
原创粉丝点击