【LeetCode】拓扑排序

邻接表存储和遍历的标准模板

拓扑排序 模板

  • 拓扑排序
    用bfs来访问所有的节点,把入度为0的节点加入到队列中;每次从队列中取出一个节点,相当于从图删除这个节点,这样此节点的后继节点的入度都减1,再把入度为0的节点加到队列中。
  • 时间复杂度
    时间复杂度 O(n+m), n 表示点数,m 表示边数
  • java 模板
    用邻接表存储
    BFS遍历队列

图的存储结构

由于树是特殊的图,所以我们存储树也是用的邻接表或邻接图。
邻接表是指对于图上的每个结点来说,用一个单链表存储它的临接点。
在这里插入图片描述
我们需要h[],e[],ne[],idx来表示这个邻接点:

  • h[v] : 指向节点v形成的链表的头节点
  • e[i] : 第i个点的值v(表示下标和值的映射)
  • ne[i] : 表示邻接表链表中 i 节点的下一个节点
  • idx : 当前遍历到的节点的索引,等边都插入完idx就是节点个数

在节点a的后面插入b:
idx为当前遍历到的节点即b,因此e[idx] = b
我们用头插法插入到a的那条邻接表,h[a]为a的邻接表的头节点,所以ne[idx] = h[a]
头节点变成我们新插入的节点b

    private static void add(int a, int b){
   
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }

有权重

有权重还需要一个w[i]来存储当前边的权重

  • w[i]: 指i的权重

构建邻接表:
其中a->b, c为a到b的权重

void add(int a, int b, int c) {
    //构建邻接表
    e[idx] = b;
    w[idx] = c;
    ne[idx] = h[a]; 
    h[a] = idx++;  //h[a] 一直指向a邻接表头插法起点,其实是最后一个,指针保留的方式也是向前
}
1. idx一直向前,如果a是第一次出现,则h[a]的值对应ne中位置即是起点。
2. 插入的方式是类似头插法,每次邻接表中的新元素出现,则插入邻接链表的第一个。也可以这样理解,是每次插到最后,让h[a]指向最后一个元素,遍历的时候倒着向前遍历。
3. 如果指向下一个为空时,指针值为-1.

拓扑排序

这种方法队列是用数组q表示的,hh指向队首节点 初始化为0,tt指向最后一个节点初始化为-1;
当hh<=tt 说明队列中有元素,就进行遍历。
最后如果所有元素都入过队,即tt==n-1 就说明有拓扑序列

    private static boolean topsort(){
   
        // 把入度为0的节点入队
        for (int i = 1; i <= n; i++) {
    // i是点的编号 看题目的编号是如何给的
            if(d[i]==0){
   
                q[++tt] = i;//入队
            }

        }
        // BFS 访问
        while(hh <= tt){
   
            // 取队头节点t
            int t = q[hh++];
            // 遍历t的单链表,删除节点t,所以将节点t的所有后继j的入度-1
            for (int i = h[t]; i != -1; i = ne[i]) {
   
                int j = e[i];  // 索引对应的值 因为入度用值作为下标
                if(--d[j] == 0){
   
                    q[++tt] = j; // 入度为0加入队列
                }

            }
        }
        // 如果所有n个节点都加入过队列,就存在拓扑序
        return tt == n - 1;
    }

直接用Queue表示队列

AcWing 848. 有向图的拓扑序列

【题目描述】
给定一个n个点m条边的有向图,点的编号是1到n,图中可能存在重边和自环。
请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出-1。
若一个由图中所有点构成的序列A满足:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。
【输入格式】
第一行包含两个整数n和m
接下来m行,每行包含两个整数x和y,表示存在一条从点x到点y的有向边(x, y)。
【输出格式】
共一行,如果存在拓扑序列,则输出拓扑序列。
否则输出-1。
【数据范围】
1≤n,m≤105
【输入样例】
3 3
1 2
2 3
1 3
【输出样例】
1 2 3


import java.util.Arrays;
import java.util.Scanner;

/**
 * @author flora.zxf
 * @date 2021/6/18
 */
public class Tuopu {
   
    static int N 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值