【LeetCode】树与图的dfs和bfs

参考:
lzh的笔记

树与图的存储结构:邻接表

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

  • h[v] : 指向节点v形成的链表的头节点注意初始化为-1
  • 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.

DFS

DFS模板

用邻接表存储:h[],e[],ne[],idx
既然用邻接表存了,要注意如何判断和一个节点u相邻的另一个节点j ,哪一个是父节点。我们用st数组表示一个节点有没有被遍历过,由于从根节点开始遍历,所以父节点一定先于子节点访问,所以只有判断visted记录j有没有访问过就可以了。一定有且只有一个访问过的j,它是u的父节点。

    private static int dfs(int u){
   
        // 记录u被遍历过了
        visited[u] = true;
        for(int i=h[u];i!=-1;i=ne[i]){
   
            int j = e[i];
            // 跳过父节点
            if(!visited[j]){
   
               dfs(j);
            }
    }

模板题:AcWing 846. 树的重心

【题目描述】
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
【输入】
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
【输出】
4


【思路】
首先明白题目说的意思,把这个点删除后 剩余各个连通块中点数的最大值最小;也就是剩余联通块的节点数最多的值
如下图 把中间的蓝色节点删除后,剩下的连通块

  • 根节点的连通块,节点数为3
  • 剩下的三个子节点,节点数分别为1
    因此最大值是3
    我们要找的是遍历把每个节点都删除,找到剩下的联通块的最大值,然后再min
    在这里插入图片描述
    要求删除某个节点后 剩余节点的连通块个数:
  • dfs每个节点
    • 求其每个子节点的连通块大小,找到最大值
    • 用总节点个数减去当前节点的联通块大小 得到根节点的连通块
    • 将1和2取最大值,得到当前节点各个连通块中点数的最大值
    • min(ans,上一步求的值)
import java.util
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值