带权图的最小生成树

//最小生成树定义:n个顶点,n-1条边连接,路径之和最小
//算法思想:先取一个顶点,找可能路径最小的边,然后这2个顶点对剩余顶点的边中取最小的,以此进行下去,最后就是最小生成树

附上一个讲的很好的链接https://blog.csdn.net/luoshixian099/article/details/51908175

//边
class Edge {
    int start;
    int end;
    int distance;

    public Edge(int s, int e, int d) {
        start = s;
        end = e;
        distance = d;
    }

}
//优先级队列,实际中会用堆代替基于数组或链表的队列吧
class PQueue {
    final int size;
    int curSize;
    Edge[] array;

    public PQueue(int size) {
        this.size = size;
        curSize = 0;
        array = new Edge[size];
    }

    // 从大到小
    public void add(Edge e) {
        int i;
        for (i = 0; i < curSize; i++)
            if (e.distance >= array[i].distance)
                break;
        for (int j = curSize - 1; j >= i; j--) {
            array[j + 1] = array[j];
        }

        array[i] = e;
        curSize++;
    }

    public Edge removeMin() {
        return array[--curSize];
    }

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

    public int size() {
        return curSize;
    }

    public Edge peekN(int n) {
        return array[n];
    }

    public int find(int index) {
        for (int j = 0; j < curSize; j++)
            if (array[j].end == index)
                return j;
        return -1;
    }

}

class Vertex {
    char label;
    boolean inTree;

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

public class Graph {
    private final int noEdge = -1;// 如果没有边,距离设置为-1
    private final int maxVer;
    private Vertex[] vertex;
    private int[][] adjMat;
    private int curVer;// 当前顶点index
    private int nVers;// 当前顶点数
    private int nTree;// 在树中的顶点数
    private PQueue queue;

    public Graph(int size) {
        nTree = 0;
        nVers = 0;
        maxVer = size;
        vertex = new Vertex[maxVer];
        queue = new PQueue(maxVer);
        adjMat = new int[maxVer][maxVer];
        for (int i = 0; i < maxVer; i++)
            for (int j = 0; j < maxVer; j++)
                adjMat[i][j] = noEdge;// 初始值
    }

    public void addVer(char label) {
        vertex[nVers++] = new Vertex(label);
    }

    // 假设无向
    public void addEdge(int ver1, int ver2, int distance) {
        if (ver1 == ver2)
            return;
        adjMat[ver1][ver2] = distance;
        adjMat[ver2][ver1] = distance;
    }

    public void displayVer(int key) {
        System.out.print(vertex[key].label);
    }

    public void mst() {
        curVer = 0;// 这个起始点是任意的,0-5全试过
        while (nTree < nVers - 1) {
            vertex[curVer].inTree = true;
            nTree++;
            for (int j = 0; j < nVers; j++) {
                if (j == curVer)// 排除自己
                    continue;
                if (vertex[j].inTree)// 已经在队列中
                    continue;
                int distance = adjMat[curVer][j];
                if (distance == noEdge)// 如果2个顶点无边
                    continue;
                putInQueue(j, distance);
            }
            if (queue.size() == 0) {
                System.out.println("graph has not been connected");
                return;
            }
            Edge edge = queue.removeMin();
            int start = edge.start;
            curVer = edge.end;
            System.out.print(vertex[start].label);
            System.out.print(vertex[curVer].label);
            System.out.println();
        }
        for (int i = 0; i < nVers; i++) {
            vertex[i].inTree = false;
        }
    }

    private void putInQueue(int j, int distance) {
        int index = queue.find(j);
        if (index != -1) {
            Edge edge = queue.peekN(index);
            int oldDist = edge.distance;
            // 如果队列里最大的距离大于添加的距离,就移除它,因为每次选最小距离
            // 而如果要添加的距离大于等于它,则不予添加
            if (oldDist > distance) {
                queue.removeN(index);
                Edge newEdge = new Edge(curVer, j, distance);
                queue.add(newEdge);
            }
        } else {// 如果队列里没有以j为终点的边,直接添加
            Edge edge = new Edge(curVer, j, distance);
            queue.add(edge);
        }

    }

    public static void main(String[] args) {
        Graph g = new Graph(20);
        g.addVer('A');
        g.addVer('B');
        g.addVer('C');
        g.addVer('D');
        g.addVer('E');
        g.addVer('F');
        g.addEdge(0, 1, 6);
        g.addEdge(0, 3, 4);
        g.addEdge(1, 2, 10);
        g.addEdge(1, 3, 7);
        g.addEdge(1, 4, 7);
        g.addEdge(2, 3, 8);
        g.addEdge(2, 4, 5);
        g.addEdge(2, 5, 6);
        g.addEdge(3, 4, 12);
        g.addEdge(4, 5, 7);
        g.mst();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值