使用栈的后序遍历
第一种:不推荐,比较麻烦。定义一个结构体,增加flag标志。
<span style="font-size:14px;">#ifndef TRITREE_HEADER
#define TRITREE_HEADER
using namespace std;
#include<stack>
#include<queue>
#include<list>
#include<algorithm>
#include<iterator>
#include<assert.h>
template<class T>
class TNode
{
public:
TNode() { lchild = rchild = parent = nullptr; };
T data;
TNode<T>* lchild, *rchild, *parent;
};
template<class T>
struct FNode//为非递归后序遍历创建的结构体数据
{
TNode<T>* m_pNode;
bool m_bflag;
FNode(TNode<T>* pNode, bool bflag)
{
m_pNode = pNode; m_bflag = bflag;
}
};
template<class T>
void TriTree<T>::PostOrderByflag(TNode<T>* bt)
{
printf("非递归后序遍历:");
if (nullptr == bt)
{
return;
}
stack<FNode<T>> SNode;
while (nullptr != bt || !SNode.empty())
{
while (nullptr != bt)
{
//fasle 表示 只遍历过左子树 此时还不能输出根节点
SNode.push(FNode<T>(bt, false));
bt = bt->lchild;
}
while (!SNode.empty() && SNode.top().m_bflag)
{
//true表示 已经遍历过该节点 右子树 可以输出根节点了
cout << SNode.top().m_pNode->data << " ";
SNode.pop();
}
if (!SNode.empty() && !SNode.top().m_bflag)
{
bt = SNode.top().m_pNode;
SNode.top().m_bflag = true;
bt = bt->rchild;
}
}
puts("");
}</span>
第二种:使用双栈,将1栈淡弹出元素压入二栈,二栈依次弹出便可以达到后序遍历效果。
template<class T>
void TriTree<T>::PostOrderByDoubleStack(TNode<T>* bt)
{
if (nullptr == bt)
{
return;
}
stack<TNode<T>*> Process;
stack<TNode<T>*> Result;
TNode<T>* pTemp = nullptr;
Process.push(bt);
while (!Process.empty())
{
pTemp = Process.top();
Result.push(pTemp);
Process.pop();
if (nullptr != pTemp->lchild)
{
Process.push(pTemp->lchild);
}
if (nullptr != pTemp->rchild)
{
Process.push(pTemp->rchild);
}
}
while (!Result.empty())
{
Visited(Result.top());
Result.pop();
}
puts("");
}
第三种:使用单栈,增加一个临时变量标记它的左子树与右字数是否被访问。由于是自底向上,如果临时节点不为当前节点的左孩子或右孩子,那么当前节点左子树与右子树已经被访问。template<class T>
void TriTree<T>::PosOrderBySingleStack(TNode<T>* bt)
{
if (nullptr == bt)
{
return;
}
TNode<T>* pCur = bt;
TNode<T>* pLast = bt;//初始化 这个一定要注意 从根节点开始
stack<TNode<T>*> SNode;
SNode.push(bt);
while (!SNode.empty())
{
pCur = SNode.top();
if (nullptr != pCur->lchild&&pLast != pCur->lchild
&&pLast != pCur->rchild)
//如果当前节点的左孩子或者右孩子 等于 刚刚打印过的节点
//则当前节点的左子树已经处理 否则就压栈
{
SNode.push(pCur->lchild);
}
else if (nullptr != pCur->rchild&&pLast != pCur->rchild)
{
//如果上一次打印节点 与当前节点右孩子相同 表明右子树已经打印
SNode.push(pCur->rchild);
}
else
{
//打印当前节点 更新最近打印节点 弹栈
SNode.pop();
Visited(pCur);
pLast = pCur;
}
}
puts("");
}