二叉树遍历之后序遍历(递归和非递归)

二叉树后序遍历
1、图示分析:
二叉树的后序遍历顺序是:左、右、根,这与前两个遍历相同的一点就是都需要辅助栈来保存左,也就是在循环向最左的时候一路遇到的根。但是后序遍历不能直接弹出栈顶元素打印,我们要先判断一下通过栈顶元素是否有右,如果有,要先处理右侧,然后在返回来处理它,让我们通过一个图来深入的理解一下
在这里插入图片描述

首先 元素1保存,向左走,1的左2保存,向左走,2的左4保存,向左走,然后元素4的左是空,则此时栈内3个元素,1,2,4;我们不能直接弹出栈顶4,要先看元素4有没有右侧,没有,好,弹出4打印4,现在栈顶元素是2,2有右吗?有,保存5,现在栈顶元素是5,5有右吗没有,弹出5打印5,现在栈顶元素是2,有右吗?有,好了那么现在问题来了,我们已经处理过了2的右侧5,可是我们如何知道5被处理过了呢?假如说我们已经通过某种方式知道了5被处理过了,我们接着分析,栈顶元素2有右吗?有,处理过吗?处理过,弹出2,打印2,栈顶元素是1,1有右吗?有3,处理过吗?没有,保存入栈,现在栈顶元素是3,3有右吗?有6,处理过吗?没有,保存入栈,此时栈内元素1,3,6;栈顶元素有右吗?没有,弹出6打印6,栈顶元素3有右吗?有,处理过吗?处理过,弹出3打印3,栈顶元素1有右吗?有,处理过吗?处理过,弹出1打印1。栈内元素个数为0,结束。所以我们现在要解决的问题就是如何知道我们有一些结点是被处理过的,我们现在已经知道了在什么条件下可以弹出打印栈顶元素,那就是栈顶元素的右为空,或者是栈顶元素的右已经被处理过。然后栈顶元素的右不为空且没有被处理过则就要入栈保存。这些被处理过的元素都有一个共同的特点就是他们都会入栈然后被弹出,那么我们在它被弹出打印的时候标记一下这个变量,如果下一次栈顶元素的右与刚才我们标记的元素相同,我们就可以弹出打印栈顶元素了,因为这证明栈顶元素的右已经被处理过了。左,右,根,右已经被处理过,自然要打印根。
2、非递归遍历代码

void UnRecLastTravresal(BinaryTree *pTree)
 {
    
    
     if(pTree == NULL) return;
 
     Stack *pStack = NULL;
     s_Init(&pStack);
 
     BinaryTree *pMark = NULL;
     while(1)
     {
    
    
         while(pTree)
         {
    
    
             //保存 向左走
             s_Push(pStack,pTree);
             pTree = pTree->pLeft;
         }
         if(pStack->nCount == 0) break;
 
         //栈顶元素的右
         if(pStack->pTop->nValue->pRight == NULL || pStack->pTop->nValue->pRight == pMark)
         {
    
    
 
             //弹出 打印 标记
             pMark = s_Pop(pStack);
             printf("%d ",pMark->nValue);
         } 
         else
         {
    
    
             //右
             pTree=pStack->pTop->nValue->pRight;
         }
     }
     printf("\n");
 }

3、递归代码

 void LastorderTraversal(BinaryTree *pTree)
   {
    
    
       if(pTree == NULL) return;
 
       LastorderTraversal(pTree->pLeft);

       LastorderTraversal(pTree->pRight);

	   printf("%d ",pTree->nValue);
   
  }

猜你喜欢

转载自blog.csdn.net/scarificed/article/details/112798278