二叉树的非递归后序遍历

昨天写了二叉树的先序、中序的非递归遍历,今天写的是二叉树的后序非递归遍历,为什么将后序和前边两个分开写,因为后序并不是想递归那样直接在先序上进行一个简单的更改就行了,非递归的情况是这三种之中最复杂的。为什么这么说?因为按正常思维来说写出来的后序遍历是很容易陷入一个死循环之中的。

 

还是拿之前的图来说,后序遍历的话你需要先访问完1的左子树,然后右子树,然后再是1.想访问2的话就是先访问3,4。正常来想后序不过是依然一直向最下层的左子树走,依然是将走过的节点放到栈里边,访问完3之后获取栈顶元素2,但是这时候是不能让他出栈的,如果出的话访问完2的右子树的时候再去找2这个数据就找不到了。所以你这时候只能是获取栈顶元素的数据,不出栈。然后去访问他的右子树4,访问完了,这时候怎么办继续回,也就是去找2,这时候就需要让2出栈了,因为已经访问完2这棵树了。思想是很好,但是你怎么让你的程序判定,你这是第一退回来2还是已经访问完他的右子树要把2出栈,当你从4回退到2之后,如果没有条件判定,你的程序是不知道你这是第二次来2了,以为是第一次,他就又去访问2的右子树。导致变成了一个死循环一直在右子树那里不停的遍历。

  这里当然会有很多的解决办法,比如你再创建一个栈,另一个栈用来存储一个标志,你入一个元素,这个栈就入个0,第一次退回来就把他对应的标志栈变成1,第二次回来就让对应的标志栈变成2,2的时候就让你的元素出就可以了。等等解决方法,不过今天我要解释的是一个很简单,却很巧妙的一个方法。

  在你的程序之中再创建一个prev变量。拿程序来一步一步说。

void BTreePostOrderNonR(BTNode* root)

{

assert(root);

Stack S;

StackInit(&S, 100);

BTNode *cur = root;

BTNode *top = NULL;

BTNode *prev = NULL;

while (cur || StackEmpty(&S))

{

 

while (cur)

{

StackPush(&S, cur);

prev = cur;

cur = cur->_left;

}

top = StackTop(&S);

if ((top->_right != NULL) && (top->_right != prev))

{

cur = top->_right;

}

else

{

printf("%d", top->_data);

StackPop(&S);

prev = top;

}

}

}


在程序开始还是那个问题,一直走到程序左子树的最下层。但是这里边有一个和以前不同就是每次在移动cur之前,先将当前的cur给了prev,prev这个指针通过名字就知道他是要干什么的,就是来存储你当前访问的前一个节点地址。

 之后同样获取他的top,但是获得之后需要进行判断,当前的top的右孩子是不是等于你的prev,就拿上图来说,当你第一次走到1的时候,你的prev应该是2,但是当你第二次通过右子树退回来再到1的时候就是5,也就是你top节点的右孩子了。所以说当你的prev等于你当前top 的右孩子时那就说明已经访问过了,不需要再去访问他的右孩子了,这时候将这个元素出栈就可以了。但是这里还需要加一个判断条件,也就是top->_right != NULL  为什么需要加一个这个判断条件,就拿这个图来说吧,如果不加这个条件你就会发现你的程序一个数字也输出不出来,会陷入到一个死循环中,为什么会这样呢?首先你看你的3结点,他有两个孩子,你访问完他的左孩子之后是不是应该去访问他的右孩子,但是当你左右都为NULL的时候,是不是程序就混乱了,本来还没有访问你的右边,但是你现在top->_right == prev就是等于他的,因为你的左右都为NULL,这时候程序就会出现问题。所以就需要加上判断条件如果右孩子是空那就直接别走了。

 

程序是没有问题的,这里我再把栈的一些函数给了大家。

typedef struct Stack

{

STDataType* _st;

size_t _size;

size_t _capacity;

}Stack;

 

 

 

void StackInit(Stack* s, size_t capacity)

{

assert(s && capacity > 0);

s->_st = (STDataType*)malloc(sizeof(STDataType)*capacity);

assert(s->_st);

s->_size = 0;

s->_capacity = capacity;

}

 

void StackPush(Stack* s, STDataType x)

{

assert(s);

if (s->_size == s->_capacity)

{

s->_capacity *= 2;

s->_st = (STDataType*)realloc(s->_st, sizeof(STDataType)*s->_capacity);

}

 

s->_st[s->_size++] = x;

}

 

void StackPop(Stack* s)

{

assert(s && s->_size);

 

--s->_size;

}

 

STDataType StackTop(Stack* s)

{

assert(s && s->_size);

 

return s->_st[s->_size-1];

 

}

size_t StackSize(Stack* s)

{

assert(s);

return s->_size;

}

 

// 空返回0,否则返回非零

int StackEmpty(Stack* s)

{

return s->_size;

}


猜你喜欢

转载自blog.csdn.net/hanani_jia/article/details/80057630