算法-树与图的深度优先遍历

树是一种特殊的图,是无环连通图。图分成有向图和无向图。ab无向边处理相当于a到b的有向边和b到a的有向边组成。所以简化为我们只用考虑有向图。

有向图存储方式:

  • 邻接矩阵 ——> g[a][b] 存储 a——>b边的信息 空间复杂度:(n^2)
  • 邻接表(常用)单链表存储
    注意:深度优先搜索和宽度优先搜索每个点都只会遍历一次

思路:

1.用数组存储图,需要idx存储边的下标索引,h[i]数组存储数字i指向的第一个数字,ne[i]存储与第i条边同起点的下一条边的idx,e[i]存储第i条边连向的终点
2.还需要一个boolean型数组st[]记录当前点有没有被走过,由于每个点只会经过一次,所以并不需要进行恢复现场的操作
3.从第一点进行遍历,走到链表存储的下一个点,如果没有被走过,就递归搜索该点链表存储的数字。

详解:

1.h[]数组的详解(见下图)
在这里插入图片描述
2.插入操作(保存边的关系)
在这里插入图片描述

题目:

在这里插入图片描述
在这里插入图片描述

详解(Java)

import java.util.Scanner;

public class 树与图的深度优先遍历 {
    static int N = 100010,M = N * 2;//N节点数量,M边的数量,由于是无向图,所以边的数量是点的数量的2倍
    static int[] h = new int[N];//h[i] 表示 i为起点 连向的 第一个点的 下标索引idx
    static int[] e = new int[M];//e[i] 表示 边i 连向的 终点
    static int[] ne = new int[M];//ne[i] 表示 与第i条边 同起点的 下一条边的 下标索引idx
    static int idx;//边的下标索引
    static boolean[] st = new boolean[N];//存点有没有走过
    static int ans = N;//记录最小的最大值
    static int n;

    //初始化,每个点一开始都没有连接边,值都为-1
    public static void init(){
        for (int i = 1; i < N; i++) {
            h[i] = -1;
        }
    }

    //链表中插入值(一般都是在第一个插入)
    public static void add(int a,int b){
        e[idx] = b;//表示加入边的 终点的节点
        ne[idx] = h[a];//表示 与加入边的 同起点的 下一条边的终点为 原先以a为起点 连向的第一个点的下标索引
        h[a] = idx++;//表示 现在的以a为起点 连向的第一个点的 下标为新加入的 点b的下标索引,再让下标索引自增方便下一个新点的加入
    }

    //返回以u为根的 子树中 点的数量
    public static int dfs(int u){
        st[u] = true;//标记当前点已经被搜过了
        int sum = 1;//以u为根的子树 点的数量 要把u自身算进去
        int res = 0;//每个连通块的最大值
        for (int i = h[u]; i != -1 ; i=ne[i]) {//从点u连向的边中的头节点开始,直到u连向的边全部搜完
            int j = e[i];//节点的下标赋值给j
            if(!st[j]){//当j没有被搜过时
                //dfs(j) ——> 搜索点j连向的点
                int s = dfs(j);//当前子树的大小
                res = Math.max(res,s);
                sum+=s;
            }
        }
        //n-sum 为删除点的 上面的 连通块的大小
        res = Math.max(res,n-sum);
        ans = Math.min(ans,res);
        return sum;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        //初始化
        init();
        for (int i = 0; i < n-1; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            //无向边,分别指向对方
            add(a,b);
            add(b,a);
        }
        dfs(1);
        System.out.println(ans);
    }
}

树与图的深度优先遍历,主要是理解遍历方式,有了前面DFS的学习,注重如何实现。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值