要通过非递归的方式实现二叉树的后续遍历,需要注意以下几点:
1. 后续遍历中,因为先访问左子树,因此,我们需要先找到该二叉树的最“左下”的子树,即这棵目标树的左子树为空。
2. 如果最左下的子树其根节点仍有右子树,根据后续遍历“左右根”的原则,需要先访问完右子树,再对其根节点进行访问,因此,非递归后续遍历的难点就在于如何处理“最左下”子树的根节点仍有右子树的问题。
针对问题2,我们需要设立一个指向最近访问节点的指针r,即BiTNode * r = NULL(注意初始化为空指针,否则报未初始化异常的错误),之后,思路是:如果最左子树的右子树没有访问过,就对其右子树重复后续非递归遍历的步骤,如果被访问过,则令r指向右子树的根节点!
具体代码如下:
Bitree Non_Recursive_postorder(Bitree T) {
if(T == NULL || (T->lchild == NULL && T->rchild == NULL)) {//空树或单节点树直接返回
return T;
}
StackNode S; Bitree p = T;
stackInit(S);
Bitree r = NULL;//r始终指向最近访问的节点
while (p || !isEmpty(S)) { //循环出口
if (p) {
stackpush(S, p);
p = p->lchild;//走到最左
}
else {
p = getTop(S);
if (p->rchild && p->rchild != r) {
p = p->rchild;
}
else {
visits(stackpop(S, p));//导出当前栈顶节点并访问
r = p;//r始终指向最近访问的节点
p = NULL;
}
}
}
return T;
}
main函数用于测试:
int main() {//建树
Bitree T = (BitNode*)calloc(1, sizeof(BitNode));
T->lchild = (BitNode*)calloc(1, sizeof(BitNode));
T->rchild = (BitNode*)calloc(1, sizeof(BitNode));
T->data = 'a';
T->lchild->data = 'b';
T->rchild->data = 'c';
Non_Recursive_postorder(T);
}
最后,附上宏定义及接口:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef char ElemType;
#define MaxSize 50
typedef struct BitNode {
ElemType data;
struct BitNode* lchild;
struct BitNode* rchild;
}BitNode,*Bitree;
typedef struct Stack {
Bitree data[MaxSize];
int top;
}StackNode;
void stackInit(Stack &S) {
S.top = -1;
}
bool stackpush(Stack &S,BitNode *e) {
if (S.top == MaxSize - 1) {
printf("栈满错误");
return false;
}
else {
S.data[++S.top] = e;
}
return true;
}
Bitree stackpop(Stack &S, Bitree& e) {
if (S.top == -1) {
printf("空栈异常");
exit(0);
}
else {
e = S.data[S.top--];
}
return e;
}
bool isEmpty(Stack S) {
if (S.top == -1) {
return true;
}
else {
return false;
}
}
Bitree getTop(Stack S) {
return S.data[S.top];
}
void visits(Bitree T) {
if (T != NULL) {
printf("%3c", T->data);
}
}