图,树,图的遍历顺序(Graphs,Trees and Traversal Oreder of Graphs)
作者:互联网
图,树,图的遍历顺序(Graphs,Trees and Traversal Oreder of Graphs)
主要介绍在编译器中使用到的图、树和图的遍历顺序。
图 Graphs
在图论中,图是一种数学结构,用来表示一组对象,这些对象之间有一些成对的关系。对象可以包含任意信息,例如单个值、某段代码或公司员工的姓名,具体取决于图的用途。
这里我们尽可能简单地用一个字母标识每个对象,将图中对象成为顶点(vertices),对象间关系成为边(edges)。使用 G = ( V , E ) G = (V,E) G=(V,E) 描述顶点V 和边E 的集合,顶点V 的个数为 n = ∣ V ∣ n = |V| n=∣V∣,边的个数 m = ∣ E ∣ m = |E| m=∣E∣。
边用于描述顶点的移动,这种移动称为路径,边可以是有方向的,也可以是无方向的。也就是说,通过多个顶点到顶点的边,可能从顶点y到达顶点v。图中y到v的路径可以记为: y ∗ → G v _y \ \underrightarrow{*}_G\ {_v} y ∗G v 。图可以有一个根节点r,表示图的起点,这时候图记为 G = ( V , E , r ) G=(V,E,r) G=(V,E,r)。
本文中,图中的边用虚线边,树的边用实线边,下面是一个有向图。
树 Trees
树是图的子集,这意味着树由相同的元素组成,例如顶点、有向边、无向边和根。树中不能有任何循环路径,因此树中的顶点具有层次顺序。这意味着每个顶点都与树中的其他顶点有某种关系。下面介绍树T的一些关系。
- 根 Root:树顶部的顶点,记为r。
- 路径 Path:树中的路径是连接一个顶点到另一个顶点的顶点和边的序列,顶点y到顶点v的路径记为 y ∗ → T v _y \ \underrightarrow{*}_T\ {_v} y ∗T v 。
- 深度 Depth:一个顶点v的深是路径 r ∗ → T v _r \ \underrightarrow{*}_T\ {_v} r ∗T v上边的数目。
- 父亲 Parent:如果在树上存在一个边 ( p , v ) (p,v) (p,v),则顶点p是顶点v的父亲。
- 孩子 Child:如果在树上存在一个边 ( p , v ) (p,v) (p,v),则顶点v是顶点p的父亲。
- 兄弟 Sibling:有相同父亲的顶点。
- 祖先 Ancestor:如果a在路径 a ∗ → T v _a \ \underrightarrow{*}_T\ {_v} a ∗T v (包括v)上,则顶点a是v的祖先。
- 后代 Descendant:顶点a是顶点v的祖先,则v是a的后代,包括顶点自己。
- 真祖先 Proper Ancestor:和祖先的一样,但不包括自己,真祖先a到顶点v的路径记为: a + → T v _a \ \underrightarrow{+}_T\ {_v} a +T v 。
- 真后代 Proper descendant:和后代一样,但不包括自己。
- 子树 Subtree:顶点v是树中的一个顶点,有v和其后代组成的的树为T的子树,顶点v是该子树的根。
- 单体 Singlenton:只有一个顶点的树。
- 森林 Forest:森林就是一系列的树,这些树不互相连接。
遍历顺序 Traversal Order
遍历一个图或树,就是访问他们的每个节点。图和树的遍历顺序非常多,这里介绍一种叫做深度优先搜索 (DFS:Depth-First-Search)方法,并由此产生的四种遍历顺序。
深度优先搜索算法:沿着图或树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
并由DFS产生4种遍历顺序:
- 前序遍历 Pre-order:以DFS搜序一个顶点没有编号的图,每个定点在发现时进行编号,这个顺序就是前序遍历。
- 后序遍历 Post-order:一个顶点所有出边到达的顶点都被访问过后,它所获得的编号。
- 逆前序 Reverse pre-order:前序的逆序。
- 逆后序 Reverse post-order:后序的逆序。
这个图中,所有黑色线都是图的一部分,但是只有直线是图的DFS生成的树(DFST: Depth-Fist Spanning Tree)的一部分,红线是DFS的搜索路径。
在龙书介绍了DFS的算法,以上面这个有向图为例。
对于逆后序(RPO),又称为深度优先排序(depth-first order)是编译器中做数据流迭代时候常选用的遍历顺序,它可以加快求解不动点的速度。
DAG的拓扑排序,就是任意一条边 n->m,节点 n 都先于节点 m 。
对于有向无环图(DAG),其实逆后序就是拓扑排序。如果一个有向图没有环的话,也就是一个DAG,已拓扑排序或者RPO顺序遍历只需要一次迭代便可以收敛(得到不动点),因为根据拓扑排序的定义可以知道,访问一个节点前它的前驱都已经访问过了。
但对于有环的有向图CFG,其实不存在拓扑排序,这时候已逆后序RPO顺序遍历,可以加速算法。
参考
- [1] Algorithms for Finding Dominators in Directed Graphs
- [2] 龙书
标签:遍历,路径,Trees,Traversal,Graphs,顺序,顶点,节点 来源: https://blog.csdn.net/Dong_HFUT/article/details/121388725