拓扑排序(TopologicalSort) Java实现

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称之为AOV网(Active On Vertex Network

AOV网不能存在回路

拓扑排序含义

G=(V,E)是一个具有n个顶点的有向图,V中的顶点序列V1,V2,....,Vn满足若从顶点ViVj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前。则我们称这样的顶点序列为一个拓扑排序。

所谓拓扑排序,其实就是对一个有向图构造拓扑序列的过程

拓扑排序算法(TopologicalSort

AOV网进行拓扑排序的方法和步骤如下:

1.AOV网中选择一个没有前驱的顶点(该顶点的入度为0)并且输出它;

2.从网中删去该顶点,并且删去从该顶点发出的全部有向边;

3.重复上述两步,直到剩余网中不再存在没有前驱的顶点为止。


代码示例图:


代码:

public class Topological {
    
    /**
     * 顶点数组
     */
    private List<VertexNode> vexList;
    
    /**
     * 创建图(邻接表)
     */
    public void createGraph(){
        //v0
        VertexNode v0 = new VertexNode(0, 0, null);
        
        EdgeNode v0e0 = new EdgeNode(11, 0, null);
        EdgeNode v0e1 = new EdgeNode(5, 0, null);
        EdgeNode v0e2 = new EdgeNode(4, 0, null);
        
        v0.setFirstEdge(v0e0);
        v0e0.setNext(v0e1);
        v0e1.setNext(v0e2);
        
        //v1
        VertexNode v1 = new VertexNode(0, 1, null);
        
        EdgeNode v1e0 = new EdgeNode(8, 0, null);
        EdgeNode v1e1 = new EdgeNode(4, 0, null);
        EdgeNode v1e2 = new EdgeNode(2, 0, null);
        
        v1.setFirstEdge(v1e0);
        v1e0.setNext(v1e1);
        v1e1.setNext(v1e2);
        
        //v2
        VertexNode v2 = new VertexNode(2, 2, null);
        
        EdgeNode v2e0 = new EdgeNode(9, 0, null);
        EdgeNode v2e1 = new EdgeNode(6, 0, null);
        EdgeNode v2e2 = new EdgeNode(5, 0, null);
        
        v2.setFirstEdge(v2e0);
        v2e0.setNext(v2e1);
        v2e1.setNext(v2e2);
        
        //v3
        VertexNode v3 = new VertexNode(0, 3, null);
        
        EdgeNode v3e0 = new EdgeNode(13, 0, null);
        EdgeNode v3e1 = new EdgeNode(2, 0, null);
        
        v3.setFirstEdge(v3e0);
        v3e0.setNext(v3e1);
        
        //v4
        VertexNode v4 = new VertexNode(2, 4, null);
        
        EdgeNode v4e0 = new EdgeNode(7, 0, null);
        
        v4.setFirstEdge(v4e0);
        
        //v5
        VertexNode v5 = new VertexNode(3, 5, null);
        
        EdgeNode v5e0 = new EdgeNode(12, 0, null);
        EdgeNode v5e1 = new EdgeNode(8, 0, null);
        
        v5.setFirstEdge(v5e0);
        v5e0.setNext(v5e1);
        
        //v6
        VertexNode v6 = new VertexNode(1, 6, null);
        
        EdgeNode v6e0 = new EdgeNode(5, 0, null);
        
        v6.setFirstEdge(v6e0);
        
        //v7
        VertexNode v7 = new VertexNode(2, 7, null);
        
        //v8
        VertexNode v8 = new VertexNode(2, 8, null);
        
        EdgeNode v8e0 = new EdgeNode(7, 0, null);
        
        v8.setFirstEdge(v8e0);
        
        //v9 入度应为2,不是图片中的1(图片中已经改过来了)
        VertexNode v9 = new VertexNode(2, 9, null);
        
        EdgeNode v9e0 = new EdgeNode(11, 0, null);
        EdgeNode v9e1 = new EdgeNode(10, 0, null);
        
        v9.setFirstEdge(v9e0);
        v9e0.setNext(v9e1);
        
        //v10
        VertexNode v10 = new VertexNode(1, 10, null);
        
        EdgeNode v10e0 = new EdgeNode(13, 0, null);
        
        v10.setFirstEdge(v10e0);
        
        //v11
        VertexNode v11 = new VertexNode(2, 11, null);
        
        //v12
        VertexNode v12 = new VertexNode(1, 12, null);
        
        EdgeNode v12e0 = new EdgeNode(9, 0, null);
        
        v12.setFirstEdge(v12e0);
        
        //v13
        VertexNode v13 = new VertexNode(2, 13, null);
        
        vexList = new ArrayList<>();
        vexList.add(v0);
        vexList.add(v1);
        vexList.add(v2);
        vexList.add(v3);
        vexList.add(v4);
        vexList.add(v5);
        vexList.add(v6);
        vexList.add(v7);
        vexList.add(v8);
        vexList.add(v9);
        vexList.add(v10);
        vexList.add(v11);
        vexList.add(v12);
        vexList.add(v13);
        
        
    }
    
    public boolean topologicalSort() {
        //统计输出顶点数
        int count = 0;
        
        //建栈存储入度为0的顶点
        Stack<Integer> stack = new Stack<>();
        
        //统计入度数(录入也可以,但是示例图的v9的度应为2,示例图中误写为1,导致查了半天bug,自动统计入度数看来也是有必要的)
        for (int i = 0;i < vexList.size(); i++) {
            vexList.get(i).setIn(0);
        }
        for (int i = 0;i < vexList.size(); i++) {
            
            EdgeNode edge = vexList.get(i).getFirstEdge();
            while (edge != null) {
                VertexNode vex = vexList.get(edge.getAdjvex());
                vex.setIn(vex.getIn() + 1);
                
                edge = edge.getNext();
            }
        }
        
        //将入度为0 的顶点入栈
        for (int i = 0;i < vexList.size(); i++) {
            if (vexList.get(i).getIn() == 0) {
                stack.push(i);
            }
        }
        
        while (!stack.isEmpty()) {
            //栈顶 顶点出栈
            int vexIndex = stack.pop();
            System.out.print(vexIndex + "  ");
            
            count++;
            
            //从顶点表结点中取出第一个边表结点
            EdgeNode edge = vexList.get(vexIndex).getFirstEdge();
            
            while (edge != null) {
                int adjvex = edge.getAdjvex();
                
                VertexNode vex = vexList.get(adjvex);
                
                //将此 顶点的入度减一
                vex.setIn(vex.getIn() - 1);
                //此顶点的入度为零则入栈,以便于下次循环输出
                if (vex.getIn() == 0) {
                    stack.push(adjvex);
                }
                
                edge = edge.getNext();
                
            }
        }
        
        if (count != vexList.size())
            return false;
        else
            return true;
    }
    
    public static void main(String[] args) {
        Topological topological = new Topological();
        topological.createGraph();
        boolean success = topological.topologicalSort();
        
        if (success) {
            System.out.println("成功");
        }else {
            System.out.println("失败,有回路");
        }
    }

}

/**
 * 边表结点
 *
 */
class EdgeNode {
    /**
     * 邻接点域,存储该顶点对应的下标
     */
    private int adjvex;
    
    /**
     * 用于存储权值,对于非网图可以不需要
     */
    private int weight;
    
    /**
     * 链域,指向下一个邻接点
     */
    private EdgeNode next;
    
    

    public EdgeNode(int adjvex, int weight, EdgeNode next) {
        super();
        this.adjvex = adjvex;
        this.weight = weight;
        this.next = next;
    }

    public int getAdjvex() {
        return adjvex;
    }

    public void setAdjvex(int adjvex) {
        this.adjvex = adjvex;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public EdgeNode getNext() {
        return next;
    }

    public void setNext(EdgeNode next) {
        this.next = next;
    }
    
    
}

/**
 * 顶点表结点
 *
 */
class VertexNode {
    /**
     * 顶点入度
     */
    private int in;
    
    /**
     * 顶点域,存储顶点信息(下标)
     */
    private int data;
    
    /**
     * 边表头指针
     */
    private EdgeNode firstEdge;
    
    

    public VertexNode(int in, int data, EdgeNode firstEdge) {
        super();
        this.in = in;
        this.data = data;
        this.firstEdge = firstEdge;
    }

    public int getIn() {
        return in;
    }

    public void setIn(int in) {
        this.in = in;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public EdgeNode getFirstEdge() {
        return firstEdge;
    }

    public void setFirstEdge(EdgeNode firstEdge) {
        this.firstEdge = firstEdge;
    }
    
    
}

结果:


Java实现拓扑排序可以使用深度优先排序算法。首先,创建一个顶点类Vertex,其中包含一个标签属性label。然后,建立一个像(Graph)的Java抽象实现,该实现包括的顶点和边的信息。通过遍历的顶点和边,使用深度优先搜索算法来进行拓扑排序。在排序之前,可以根据需要给顶点设置优先级属性,以控制排序的精确度。实现的时间复杂度为O(|V| |E|),其中|V|表示顶点数,|E|表示边的数量。可以参考算法导论中深度优先排序算法Java实现。 下面是一个简单的Java实现示例: ```java import java.util.ArrayList; import java.util.List; import java.util.Stack; public class TopologicalSort { private List<Vertex> sortedVertices; public List<Vertex> topologicalSort(Graph graph) { sortedVertices = new ArrayList<>(); Stack<Vertex> stack = new Stack<>(); for (Vertex vertex : graph.getVertices()) { if (!vertex.isVisited()) { dfs(vertex, stack); } } return sortedVertices; } private void dfs(Vertex vertex, Stack<Vertex> stack) { vertex.setVisited(true); for (Vertex neighbor : vertex.getNeighbors()) { if (!neighbor.isVisited()) { dfs(neighbor, stack); } } stack.push(vertex); sortedVertices.add(vertex); } } class Vertex { private char label; private boolean visited; private List<Vertex> neighbors; public Vertex(char label) { this.label = label; this.visited = false; this.neighbors = new ArrayList<>(); } // getters and setters // ... } class Graph { private List<Vertex> vertices; public List<Vertex> getVertices() { return vertices; } // other methods // ... } ``` 以上是一个简单的Java实现示例,其中Graph类表示,Vertex类表示顶点。在TopologicalSort类中,topologicalSort方法使用深度优先搜索算法进行拓扑排序,最终返回排序后的顶点列表。可以根据实际需求对代码进行修改和优化。 参考链接:维基百科提供了更多关于拓扑排序的信息,可以进一步了解。中的参考资料还提供了Graph和Vertex类的代码示例。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值