二叉树遍历算法

二叉树遍历算法包含: 前序, 中序, 后序, 层次遍历 共四种算法。

先序遍历 DLR: 先访问根节点,然后访问左子树, 最后访问右子树

中序遍历LDR: 先访问左子树,然后根节点,最后访问右子树

后序遍历LRD: 先访问左子树,然后访问右子树,最后根节点

层次遍历: 从每层开始,至左向右逐层访问

先序、中序,后序都可以使用递归方式进行访问,非递归方式使用栈辅助,  层次遍历使用队列作为辅助结构

 

1. 先序非递归遍历算法:

每次递归深入的时候,就是将左右孩子节点压栈的过程,在压栈之前,访问该节点;

每个节点只有在访问完右子树,或者右子树为空时,出栈,为了标志每个节点的右孩子节点是否压栈,可以使用一个标志位flag,将节点的右孩子节点压入栈中,需要改变flag,这样每次访问栈顶元素时,如果判断右子树已访问,直接出栈;

 详细算法如下:

最开始根节点入栈

while(栈非空){

1. 获取栈顶元素cur;

2. 判断该节点的flag, 如果flag为true,说明该节点右子树已经访问,出栈, 否则 访问该节点cur;

3. 如果cur有左孩子节点,压入栈中,进入step 1;

否则,如果有右孩子节点(只有右子树),压入栈中,同时修改cur的标志位flag为true;如果cur为叶子节点,直接出栈,进入step1

}

void preOrder(BitNode *t){

if(!t) return;

Stack<BitNode*> s;

s.push(t);

BitNode *cur=NULL;

while( !s.empty() ){

cur= s.top();

if(cur.flag){

//右子树已经访问,出栈

s.pop();

}else{

visit(cur); //访问该节点

if(cur->lchild){

s.push(cur->lchild);//访问左子树

}else{

if(cur->rchild){//访问右子树

s.push(cur->rchild);

cur->flag= true;

}else{

//叶子节点

s.pop();

}

}

}

}

}

2. 中序遍历非递归算法:

与先序遍历类似,只是访问完左子树后访问根节点,访问完根节点,出栈,最后访问完右子树,为了标志每个节点的左子树是否访问,使用标志位flag

 详细算法如下:

最开始根节点入栈

while(栈非空){

1. 获取栈顶元素cur;

2. 如果cur节点标志位为flag为false, 且该节点有左子树,将左子树压入栈中,同时置该节点标志位flag为true;否则访问该节点,并出栈,如果该节点有右子树,将右孩子压入栈中

}

void inOrder(BitNode *t){

  if(!t) return;

      Stack<BitNode*> s;

      s.push(t);

      BitNode* cur=NULL;

      while( !s.empty() ){

    cur = s.top();

             if(cur->flag){

    visit(cur);

              s.pop();

            if(cur->rchild){

    s.push(cur->rchild);

    }

  }

   }//while         

}

}

3. 后序遍历二叉树非递归算法:

先访问左右子树,最后访问根节点,同样的,如果该节点的左右子树都已访问,直接出栈,否则更新节点的访问左右子树状态,如果状态为右子树已经访问,直接出栈

详细算法如下:

最开始根节点入栈

while(栈非空){

1. 获取栈顶元素cur;

2. 如果cur节点标志位为flag为2, 右子树已经访问完,访问该节点出栈, 否则,

 如果flag==1, 表明该节点左子树已经访问,开始访问右子树,如果该节点无右子树,访问该节点后直接出栈 否则,将右孩子压入栈中,同时置该节点标志位flag为2

 如果flag==0,表明该节点左右子树均未访问, 先访问左子树,如果该节点有左子树,将左子树压入栈中,同时置该节点标志位flag为1,表明左子树已经访问完, 否则判断如果该节点有右子树,将右孩子压入栈中,同时置该节点标志位flag为2,否则该节点为叶子节点,访问该节点后直接出栈

}

void postOrder(BitNode *t){

  if(!t) return;

      Stack<BitNode*> s;

      s.push(t);

      BitNode* cur=NULL;

      while( !s.empty() ){

    cur = s.top();

             if(cur->flag==2){

    visit(cur);

              s.pop();

           }else if(cur-> flag==0 ){

         if(cur->lchild){

          s.push(cur->lchild);

         cur->flag =1;

        }else{

      if(cur->rchild){

    s.push(cur->rchild);

              cur->flag=2;

    }else{

               //叶子节点

      visit(cur);

              s.pop();

            }

     }   

  }

   }//while         

}

4.层次遍历算法:

使用队列FIFO的特性,至左向右依次将根节点的孩子节点压入队列中

原文地址:https://www.cnblogs.com/energy1010/p/10627827.html