前几天数据结构课的时候,讲到二叉树的非递归遍历,老师照着严蔚敏书上的代码讲解,什么先找到最左的节点,再如何如何。。。我听得很是乱,但是我只记得之前好像在哪里看到过,其实并没有必要这么麻烦。
我首先是写出了先序的代码,个人认为思路比严的代码要清晰。
//先序遍历
S.push (m_root);
while(!S.empty())
{
p = S.top();
S.pop();
visit(p->data);
if(p->rchild)
S.push(p->rchild);
if(p->lchild)
S.push(p->lchild);
}
- 然后我就开始思考中序,发现并不那么简单,就先做后序了。后序遍历的时候,只要把弹出来的节点,依次压入另一个栈中,便可以实现了。
//另开栈的后序遍历
S.push (m_root);
while(!S.empty())
{
p = S.top();
S.pop();
P.push(p);
if(p->lchild)
S.push(p->lchild);
if(p->rchild)
S.push(p->rchild);
}
while(!P.empty())
{
visit(P.top()->data);
P.pop();
}
- 先序与后序好做,是因为我们知道什么时候访问弹出的节点,先序的话,当然是立刻访问,后序的话,就算要求最后访问,我们压到栈里就好了。可是中序的时候,我没办法知道什么时候他的左子树已经访问完了。所以我参考了一下老师的代码,发现可以用一个NULL来做标识,当访问到NULL的时候,便说明下一个节点的左子树已经访问完了,那么久可以访问了。既然这样,后序遍历时也没必要重新开一个栈了。
//中序遍历
S.push (m_root);
while(!S.empty())
{
p = S.top();
S.pop();
if(p)
{
if(p->rchild)
S.push(p->rchild);
S.push(p);
S.push(NULL);
if(p->lchild)
S.push(p->lchild);
}
else
{
visit(S.top()->data);
S.pop();
}
}
//不用另开栈的后序遍历
S.push (m_root);
while(!S.empty())
{
p = S.top();
S.pop();
if(p)
{
S.push(p);
S.push(NULL);
if(p->rchild)
S.push(p->rchild);
if(p->lchild)
S.push(p->lchild);
}else
{
visit(S.top()->data);
S.pop();
}
}
我只测试了几组数据,暂时都还是正确的。