图的遍历

797. 所有可能的路径

 

图的存储

如果需要对图进行一系列的操作,那么首选需要搞清楚图的存储方式

不同于二叉树,图的节点之间的关系相对复杂

对于一颗二叉树,邻接节点只有 0,1 或 2 个,所以用两个左右孩子指针域来保存邻接节点。「这里的邻接节点仅仅指指向的节点,而不包括被指向的节点」

对于一个图来说,其邻接节点可能有很多个,远大于树的孩子节点个数。所以这里有两种方法来存储图的信息:邻接表 & 邻接矩阵

代码形式如下:

邻接矩阵 邻接表

对于无权图来说 edges[i]=(ui,vi)

对于有权图来说 edges[i]=(ui,vi,wi)

优劣比较:

 
邻接表存储空间少无法快速判断两个节点是否邻接
邻接矩阵可以快速判断两个节点是否邻接存储空间多

树的先序遍历

在说图的遍历之间,我们首先复习一下树的遍历(只看先序遍历,其他顺序遍历同理)

下面代码的功能:输出树的所有从根节点到叶子结点的路径

图 & 树的分析对比

前面铺垫了这么多,现在正式进入本文的核心内容

其中图和树有异曲同工之处,看了下面的分析相信这种感觉更加的强烈

无环图

先来看看最简单的一种类型:无环图。这种类型不需要考虑节点是否被访问过,因为不存在环,无需考虑无限递归的可能性

树的先序遍历指出了套路的四个阶段,即:判空,先序,递归,后序。我们详细分析树和图每个阶段的不同

  1. 先来看判空递归部分

如果 graph[x] == null是不会进入递归中的,所以对于图来说,可以不需要第一步判空

对于树的递归部分来说,没有判断root.left == nullroot.right == null,所以需要第一步判空

  1. 先序后序阶段其实基本一样,这里就不详细阐述了

  2. 处理阶段

根据题目的不同要求,会有不同的处理操作。就此题需要得到所有路径来说,如果是树的话,完整路径的判断标志:是否为叶子节点;如果是图的话,完整路径的判断标志:是否到达了最后一个节点

有环图

其实有环图和无环图的唯一区别就是加了一个visited[]数组来标记节点的访问情况

然后只需要在先序部分做少许修改即可,直接上代码

多说一句:为什么对于图的遍历函数中多了一个节点参数?

其实很简单,如果是树,root就是当前需要处理的节点;而对于图,我们并不能从graph[][]中判断出当前需要处理的节点,所以需要明确指出

图的遍历

直接看一个无环图的题目 所有可能的路径