前序遍历根在最前面。实现起来比较简单,使用一个栈就OK了。
对于每一个节点,我们直接访问它,并把它的右儿子压入栈中,之后我们移动指针来访问左儿子。
到头了之后就把右儿子从站里pop出来。
ClearStack(S);
p = bt;
while (1){
if (p == NULL){
if (EmptyStack(S)) break;
p = Pop(S);
}
visit(p);
if (p->Rchild != NULL) Push(S, p->Rchild);
p = p->Lchild;
}
中序遍历的难度和前序类似。首先我们从根节点出发,一路向左走到最左边。期间遇到的节点都压栈。
之后,我们从最左侧开始访问栈中节点,并访问其右子树。
ClearStack(S);
p = bt;
while (1){
while (p){
Push(S, p);
p = p->Lchild;
}
if (EmptyStack(S)) break;
//此时应访问刚进栈的
p = Pop(S);
visit(p);
p = p->Rchild; //访问右子树
}
后序遍历相比起来复杂一些,但基本思路和中序类似。
后序遍历的顺序是 左-右-根,同样需要先向左走到头,但是回头的时候不能立刻访问根节点,而是用结构体标记一下,继续入栈,之后继续访问右节点并遍历。如果出栈的根节点是标记过的,那才说明它下面的节点都被访问过了,可以放心pop出去。
//定义栈元素类型:
typedef struct {
BTptr q; //节点地址
int tag; //标志
} STYPE;
STYPE sdata;
ClearStack(S);
p = bt;
while (1)
{
while (p)
{
sdata.q = p;
sdata.tag = 0;
Push(S, sdata);
p = p->Lchild;
}
if (EmptyStack(S)) break;
sdata = Pop(S);
p = sdata.q;
tag = sdata.tag;
if (tag == 0) //应先遍历右子树
{
sdata.tag = 1;
Push(S, sdata);
p = p->Rchild; // 访问右子树
}
else
{
visit(p);
p = NULL;
}
}