树的后序遍历特点:左–右–根
思路1:先序特点+逆序输出
先序遍历特点:根–左–右
在先序非递归遍历代码的基础上可以实现:根–右–左
如果逆序输出,就是:左–根–右
于是我们需要一个另外的栈用来逆序输出。
template<class T>
void BinaryTree<T>::PostOrder() //后序遍历
{
LinkStack<BiTreeNode<T>*>S;
LinkStack<BiTreeNode<T>*>S2; //用来逆序输出
if (root == NULL)
{
return;
}
S.Push(root);
BiTreeNode<T>* q = root;
while (!S.Is_Empty())
{
S.Pop(q);
S2.Push(q);
if (q->leftChild)
{
S.Push(q->leftChild);
}
if (q->rightChild)
{
S.Push(q->rightChild);
}
}
while (!S2.Is_Empty())
{
S2.Pop(q);
cout << q->data << " ";
}
}
思路2:先访问左右孩子,再访问父亲
1.若结点不空且左右孩子未被访问,记录结点,并指向左孩子
2.否则 如果右子树不空且右孩子未被访问,指向右孩子
3. ——否则访问栈顶
template<class T>
void BinaryTree<T>::PostOrder() //后序遍历
{
LinkStack<BiTreeNode<T>*>S;
BiTreeNode<T>* pre = root; //记录上一次访问的结点
BiTreeNode<T>* p = root; //记录当前访问结点
while (p || !S.Is_Empty())
{
if (p != NULL && pre != p->leftChild && pre != p->rightChild) //结点不空且左右孩子未被访问
{
S.Push(p);
p = p->leftChild;
}
else
{
S.Get_Top(p);
if (p->rightChild != NULL && pre != p->rightChild) //右子树不空且没被访问,入栈右孩子
{
p = p->rightChild;
}
else //访问到最后的右子树的结点后,退栈
{
S.Pop(pre);
cout << pre->data << " ";
if (!S.Get_Top(p))
{
p = NULL;
}
}
}
}
}