分析:后序遍历是三种遍历中最难的一种,后序遍历的特点为左右根,并且也需要借助一个栈来完成,如图,虚线表示p,q最开始的位置,用r指向最近访问过的结点。首先从根节点开始,沿着根的左孩子,将左孩子依次进行入栈。当D入栈之后,由于D没有右孩子,所以将D出栈,此时r指向D。
D出栈之后读栈顶元素B,p指向B,发现B有右孩子,然后将右孩子E入栈。
然后判断栈顶元素E,E没有右孩子了,所以将E出栈,此时r指向E。
然后判断栈顶元素B,B的两个孩子都已经操作过了,所以B出栈,p指向A,判断栈顶元素A,A有右孩子,右孩子C入栈,此时r指向C。
判断栈顶元素C,C无右孩子,所以C出栈,此时栈中只剩A,A的两个孩子都已经操作过了,所以A也出栈,结束,最终后序遍历结果为:DBECA
算法思想:
1、沿着根的左孩子,依次入栈,直到左孩子为空;
2、读栈顶元素进行判定,若右孩子不空且未被访问,将右孩子执行第一步;
3、栈顶元素出栈。
代码:
void PostOrder(BiTree){ // 全篇❤
InitStack(s);
BiTree *p=T,*r=NULL; // r标记最近访问过的结点
while(p!=NULL || !IsEmpty(s)){
if(p!=NULL){
push(s,p); // 一直向左走,左孩子入栈
p=p->lchild;
}
else{
GetTop(s,p);
// 获取s的栈顶元素赋值给p
// GetTop(s,p)意思就是判断栈顶元素的情况
//❤case one❤
if(p->rchild && p->rchild!=r){
// 若右孩子存在且未被访问
p=p->rchild; // 就让右孩子
push(s,p) // 入栈
p=p->lchild; // 让右孩子向左
//上面三句意思就是让右孩子的左孩子一直入栈,一直向左走
}
// ❤case two❤
else{
pop(s,p); // 右孩子为空或未被访问过,就出栈
visit(p->data);
r=p; // r标记最近访问结点
p=NULL; // r置空
// 置空原因:因为这个结点已经出栈了
//继续指向就没必要了,置空后r不标记任何结点
}
}
}
}