1、二叉树的遍历采用递归实现是比较简单的。用循环实现的话就要用到辅助栈实现。这其中前序遍历和中序遍历的循环实现又是相对容易的,这里就不再详叙了。这里主要介绍后序遍历的循环实现。
后序遍历由于遍历父节点是在遍历子节点之后,而且左节点和右节点遍历后的行为不一样,所以它的循环实现要复杂的多。
下面介绍一种采用逆后序遍历的方法来实现后序遍历。
首先看下后序遍历的定义:若二叉树非空,则依次执行如下操作: (1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点。
和前序遍历的定义对比一下:若二叉树非空,则依次执行如下操作:(1) 访问根结点;(2) 先序遍历左子树;(3) 先序遍历右子树。
是否有什么发现?是的,如果把前序遍历的第2步和第3步互换一下,则正好的后序遍历的步骤完全相反!方便起见,我把它命名为逆后序遍历,它的定义:
若二叉树非空,则依次执行如下操作:(1) 访问根结点;(2) 逆后序遍历右子树;(3) 逆后序遍历左子树。
那么逆后序遍历的结果是否也和后序遍历的结果正好相反呢,我们来验证一下:
上图的二叉树后序遍历的结果是G D B F K C A, 逆后序遍历的结果是A C K F B D G,正好相反。也就是说,只要我们能实现逆后序遍历,再将遍历结果倒置一下,就是后序遍历了。那么如何实现逆后序遍历呢,其实逆后序遍历只是将前序遍历的第2步和第3步互换了一下,只要你能实现前序遍历,一切就很简单了。
2、二叉树逆后序实现
//二叉树的逆后序遍历<pre name="code" class="cpp">template <class T>
struct BinaryTreeNode{
T m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};
template <class T>void InversePostOrder(BinaryTreeNode<T> *root){stack<T> s1;while(root != NULL && !s1.empty()){while(root != NULL){cout<<root->m_nValue;s1.push(root);root=root->m_pRight;}if(!s1.empty()){root=s1.pop();root=root->m_pLeft;}}}
然后将逆后序遍历的结果倒置。倒置的操作可以采用一个栈实现,把输出的顺序存到一个栈中,再输出。
template <class T>
void InversePostOrder(BinaryTreeNode<T> *root)
{
std::stack<T> s1;
std::stack<T> s2;
while(root != NULL && !s1.empty())
{
while(root != NULL)
{
//cout<<root->m_nValue;
s2.push(root);
s1.push(root);
root=root->m_pRight;
}
if(!s1.empty())
{
root=s1.pop();
root=root->m_pLeft;
}
}
while(!s2.empty())
{
cout<<s2.pop()<<" ";
}
}