9.3 树的遍历
9.3.1 树的静态写法
这里的“树”指的是一般意义上的树,即子节点个数不限且子节点没有先后次序的树。
struct node{
typename data ; //数据域
vector<int> child ; //指针域,存放当前节点所有子节点下标
}Node[maxn]; //节点数组,maxn为节点上限个数
一般都是很人性化地给出了结点的编号,并且编号一定是0,1,…N-1(其中N为结点个数)或是1,2,.,N。在这种情况下,就不需要newNode函数了,因为题目中给定的编号可以直接作为Node数组的下标使用,非常方便。作为示例:
//vo:
Node[0].child [0] = 1, Node[0].child[1] = 2, Node[0].child[2] =3;
//V1:
Node[1].child[0] = 4, Node[1].child[1] = 5;
//v2:
Node[2] has no children, so Node[2].child.size () == 0;
//v3:
Node[3].child[0] = 6;
//v4:
Node[4] has no children, so Node[4].child.size()== 0;
//V5:
Node[5] has no children, so Node[5].child.size() == 0;
//v6:
Node[6] has no children, so Node[6].child.size() == 0;
9.3.2 树的先根遍历
对一棵一般意义的树来说,也可以采用类似二叉树的思路来进行遍历。
先跟序列为0145236
void preOrder( int root ){
cout << Node[root].data <<endl ;
for( int i = 0 ; i < Node[root].child.size() ; i++ ){
preOrder( Node[root].child[i] ) ; //递归访问当前节点root的所有子节点
}
}
9.3.3 树的层序遍历
树的层序遍历的实现方法与二叉树类似,一般使用一个队列来存放节点再数组中的下标,每次取出队首元素来访问,并将其所有子节点加入队列,直到队列为空。
//层序遍历树
void LayerOrder( int root ){
queue<int> q ;
q.push(root) ;
while( !q.empty() ){
int top = q.front() ;
q.pop() ;
cout << Node[top].data << endl ;
for( int i = 0 ; i < Node[top].child.size() ; i++ ){
q.push( Node[top].child[i] ) ; //将当前节点的所有子节点入队
}
}
}
同样的,如果需要对节点的层号进行求解,只需要在结构体node定义中增加变量来记录节点的层号:
struct node{
typename data ; //数据域
int layer; //层号
vector<int> child ; //指针域,存放当前节点所有子节点下标
}Node[maxn]; //节点数组,maxn为节点上限个数
于是树的遍历就可以写成:
void LayerOrder( int root ){
queue<int> q ;
q.push(root) ;
Node[root].layer = 1 ; //记录根结点的层号
while( !q.empty() ){
int top = q.front() ;
q.pop() ;
cout << Node[top].data << endl ;
for( int i = 0 ; i < Node[top].child.size() ; i++ ){
int child = Node[top].child[i] ;
Node[child].layer = Node[top].layer + 1 ;
q.push( Node[top].child[i] ) ; //将当前节点的所有子节点入队
}
}
}
9.3.4 从树的遍历看DFS与BFS
DFS与先跟
对所有合法的DFS求解过程,都可以把它画成树的形式,此时死胡同等价于树中的叶子结点,而岔道口等价于树中的非叶子节点,并且对这棵树的DFS遍历过程就是树的先跟遍历过程。
于是可以从中得到启发:碰到一些可以用DFS做的题目,不妨把一些状态作为树的结点,然后问题就会转换为直观的对树进行先根遍历的问题。如果想要得到树的某些信息,也可以借用DFS以深度作为第一关键词的思想来对结点进行遍历,以获得所需的结果。例如求解叶子结点的带权路径和(即从根结点到叶子结点的路径上的结点点权之和)时就可以把到达死胡同作为一条路径结束的判断。
BFS与层序遍历
事实上,对所有合法的BFS求解过程,都可以像DFS中那样画出一棵树,并且将广度优先搜索问题转换为树的层序遍历的问题。