树的遍历是比较基本的数据结构操作方法,中序遍历、线序遍历和后续遍历什么的基本上递归一下,三行代码就能搞定。但是,树的按层遍历就会稍微复杂一些。
既然是使用了栈的思想,那么,按层遍历树是否能用递归实现呢?能够使用递归的一个先决条件是当前的问题能够拆分成为子问题。
主要思想是使用栈暂存数据,一个栈用于保存当前层的节点,另外一个栈用于保存下一层的节点,在遍历该层时,将下一层的所有节点都存储到栈中,在下一次遍历中使用。
思路比较清楚,贴下这种思路的代码。
void printTreeLevel(Node *node)
{
vector<Node*> save[2];
save[0].push_back(node);
int cnt = 0;
while (save[cnt%2].size()) {
vector<Node*>::iterator it = save[cnt%2].begin();
vector<Node*>::iterator end= save[cnt%2].end();
for (;it != end;++it) {
cout<<(*it)->expr<<" ";
if ((*it)->left) {
save[(cnt+1)%2].push_back((*it)->left);
}
if ((*it)->right) {
save[(cnt+1)%2].push_back((*it)->right);
}
}
cout<<endl;
save[cnt%2].clear();
++cnt;
}
return;
}
既然是使用了栈的思想,那么,按层遍历树是否能用递归实现呢?能够使用递归的一个先决条件是当前的问题能够拆分成为子问题。
对于这个问题,一个直观的想法是这样,例如如下的一棵树 (a& b)|(c|d)&((e&f)&f|(g&i)):
一个直观的想法是这样:
- 找到最深的一个节点,遍历该节点及其兄弟节点
- 如果其父亲不为空,递归其父亲节点
- 如果为空,结束遍历
当然,按照上述方法进行遍历得到的是一颗倒着的树,但是如果把该过程反过来,那么会存在不知道哪条路径最长的问题。
但是如果将问题再简化一点,只输出指定层的节点,那么问题就被简化了很多。
因此问题被分解为:
- 获取树的深度d
- 调用d次输出函数
void printTreeLevelDG(Node *node, int nLevel)
{
if (!node || nLevel<1) {
return;
}
if (nLevel == 1) {
cout<<node->expr<<"\t";
}
printTreeLevelDG(node->left, nLevel-1);
printTreeLevelDG(node->right,nLevel-1);
}
//调用点
for (int i = 1;i<nDepth;++i) {
printTreeLevelDG(stackExpr.top(), i);
cout<<endl;
}