拓扑排序

本文介绍了有向无环图(DAG)的概念,并详细讲解了邻接矩阵和邻接表这两种图的存储结构。接着,重点阐述了拓扑排序的定义和其在有向无环图中的应用,帮助理解如何对DAG进行线性排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有向无环图

在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。
因为有向图中一个点经过两种路线到达另一个点未必形成环,因此有向无环图未必能转化成树,但任何有向树均为有向无环图。

邻接矩阵

邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中 V= [ v 1 , v 2 , … , v n ] [v_1,v_2,…,v_n] [v1,v2,,vn] 。G的邻接矩阵是一个具有下列性质的 n n n 阶方阵:

  1. 对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零(在此仅讨论无向简单图),副对角线不一定为 0 0 0,有向图则不一定如此。
  2. 在无向图中,任一顶点 i i i 的度为第 i i i 列(或第 i i i 行)所有非零元素的个数,在有向图中顶点 i i i 的出度为第 i i i 行所有非零元素的个数,而入度为第 i i i 列所有非零元素的个数。
  3. 用邻接矩阵法表示图共需要 n 2 n^2 n2 个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1)个空间。

邻接表

邻接表是图的一种最主要存储结构,用来描述图上的每一个点。对图的每个顶点建立一个容器( n n n 个顶点建立 n n n 个容器),第 i i i 个容器中的结点包含顶点 V i V_i Vi 的所有邻接顶点。实际上我们常用的邻接矩阵就是一种未离散化每个点的边集的邻接表。
在有向图中,描述每个点向别的节点连的边(点 a → a\rightarrow a b b b 这种情况)。
在无向图中,描述每个点所有的边(点 a − a- a b b b这种情况)

拓扑排序

对一个有向无环图(Directed Acyclic Graph简称DAG) G 进行拓扑排序,是将 G 中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边< u , v u,v u,v> ∈ \in E(G),则 u u u 在线性序列中出现在 v v v 之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
拓扑排序

public class TopologicalSort {
    public static void main(String [] args){
        List<Integer>[] g;
        int[] ans;
        g = generateAdjacencyList(6, new int[][] {{0, 1}, {2, 1}, {2, 5}, {3, 2}, {3, 5}, {5, 0}, {5, 4}});
        ans = topologicalSort(g);
        System.out.println(Arrays.toString(ans));
    }

    private static int[] topologicalSort(List<Integer>[] g){
        int[] ans, counts;
        int i, j, k, n;
        Queue<Integer> queue;

        n = g.length;
        ans = new int[n];
        counts = new int[n];
        queue = new LinkedList<>();
        for(i = 0; i < n; i++){
            for(j = 0; j < g[i].size(); j++){
                counts[g[i].get(j)]++;
            }
        }
        for(i = 0; i < n; i++){
            if(counts[i] == 0){
                queue.offer(i);
            }
        }
        k = 0;
        while(!queue.isEmpty()){
            i = queue.poll();
            ans[k++] = i;
            for(j = 0; j < g[i].size(); j++){
                counts[g[i].get(j)]--;
                if(counts[g[i].get(j)] == 0){
                    queue.offer(g[i].get(j));
                }
            }
        }
        return ans;
    }

    private static List<Integer>[] generateAdjacencyList(int n, int[][] edges){
        List<Integer>[] ans;
        int i, m;

        ans = new List[n];
        m = edges.length;
        for(i = 0; i < n; i++){
            ans[i] = new LinkedList<>();
        }
        for(i = 0; i < m; i++){
            ans[edges[i][0]].add(edges[i][1]);
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值