最小生成树和有向无环图的拓扑排序

最小生成树只需要在dfs基础上稍做修改,用最少的边连接所有可连接的顶点(无重复)。

拓扑排序只能用于无环图。

class Stack {
    private int[] st;
    private final int size = 20;
    private int top;

    public Stack() {
        st = new int[size];
        top = -1;
    }

    public void push(int j) {
        st[++top] = j;
    }

    public int pop() {
        return st[top--];
    }

    public int peek() {
        return st[top];
    }

    public boolean isEmpty() {
        return top == -1;
    }
}

// 顶点
class Vertex3 {
    char label;
    boolean visited;

    public Vertex3(char label) {
        this.label = label;
        visited = false;
    }

}

public class Topo {
    private final int maxVer = 20;// 最大顶点数
    private int[][] adjMat;// 邻接矩阵
    private Vertex3[] vertex;// 顶点数组
    private int curVer;// 当前顶点数
    private Stack stack;

    public Topo() {
        curVer = 0;
        stack = new Stack();
        vertex = new Vertex3[maxVer];
        adjMat = new int[maxVer][maxVer];
        for (int i = 0; i < maxVer; i++)
            for (int j = 0; j < maxVer; j++)
                adjMat[i][j] = 0;
    }

    // 添加顶点
    public void addVer(char label) {
        vertex[curVer++] = new Vertex3(label);
    }

    // 添加有向边,不是双向
    public void addAdj(int i, int j) {
        if (i == j)
            return;
        adjMat[i][j] = 1;
    }

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

    // 最小生成树,用最少的边连接所有可连接的顶点(无重复)
    // 在dfs基础上稍作修改即可
    public void mst(int index) {
        vertex[index].visited = true;
        stack.push(index);
        int k;
        while (!stack.isEmpty()) {
            int cur = stack.peek();
            k = findUnvisitedAdj(cur);
            if (k == -1)
                stack.pop();
            else {
                stack.push(k);
                vertex[k].visited = true;
                displayVer(cur);
                displayVer(k);
                System.out.print(" ");
            }
        }
        // 搜索一次后重置访问状态,便于下次搜索
        for (int i = 0; i < curVer; i++)
            vertex[i].visited = false;
    }

    // 找到一个未访问过的相邻顶点
    public int findUnvisitedAdj(int index) {
        for (int i = 0; i < curVer; i++)
            if (adjMat[index][i] == 1 && vertex[i].visited == false)
                return i;
        return -1;
    }

    // 拓扑排序:只能用于有向无环图
    // 先找到一个起始点,找后继点,“删除”起始点,循环进行。该方法效率低,不如直接删除点好吧。
    public void topo() {
        int temp = curVer;
        while (temp > 0) {
            int first = findFirst();
            if (first == -1) {
                System.out.println("\nloop(s) occur");
                return;
            }
            displayVer(first);
            vertex[first].visited = true;
            temp--;
        }
        for(int i=0;i<curVer;i++)
            vertex[i].visited=false;
    }
    //找到一个点,没有其他点指向它或指向它的点都访问过了,说明该点是找到的一个新起点
    private int findFirst() {
        a: for (int i = 0; i < curVer; i++) {
            for (int j = 0; j < curVer; j++) {
                if (adjMat[j][i] == 1 && vertex[j].visited == false)
                    continue a;
            }
            if (vertex[i].visited == false)// 不取重复值
                return i;
        }
        return -1;// 说明有环,没有环的单向图是一定有起始点的
    }

    public static void main(String[] args) {
        Topo g = new Topo();
        g.addVer('A');
        g.addVer('B');
        g.addVer('C');
        g.addVer('D');
        g.addAdj(0, 1);
        g.addAdj(0, 2);
        g.addAdj(1, 2);
        g.addAdj(2, 3);
        g.addAdj(3, 1);
        g.mst(1);
        System.out.println();
        g.topo();
    }
}


猜你喜欢

转载自blog.csdn.net/qq_26567507/article/details/80279095
今日推荐