二叉树遍历方法总结

来源:互联网 发布:增肌粉蛋白粉区别知乎 编辑:程序博客网 时间:2024/06/06 18:44

一、递归方法

1、前序遍历    :   根——左——右

Preorder_tree_walk(x){   //x为根节点

      if x != nil

          print x.key;

     preorder_tree_walk(x.left);

     Preorder_tree_walk(x.right);

}

2、中序遍历     :  左——根——右

Inorder_tree_walk(x){

    if x!=nil

       Inorder_tree_walk(x.left);

       print x.key;

       Inorder_tree_walk(x.right);

}

3、后序遍历    :  左——右——根

Postorder_tree_walk(x){

     if x!=nil

        Postorder_tree_walk(x.left);

        Postorder_tree_walk(x.right);

        print x.key;

}

二、非递归方法

比较难的是非递归方法,可以有多种方法实现。

1、前序遍历

a、第一种方法,这也是我未参考别人而写出来的,把根节点压入栈,然后若栈不为空则循环,弹出并打印出栈顶元素,压入两个孩子节点(如果有的话),再继续循环,直到栈为空

Preorder_tree_walk(x){

      stack S;

      push(S,x);

      while(S.top != null){

                x=pop(S);

                print x.key;

                if  x.left != null

                     push(S,x.left);

                if  x.right != null

                     push(S.x.right);

      }


}

b、第二种,也是标准的算法,

     处理过程如下:

     1>内层while循环:对任一节点x,如果x不为null,访问x,并把x压入栈,再令x等于x的左孩子节点,循环1,直到x为null;

     2>如果栈顶不为空,弹出栈顶元素x,并令x为x的有孩子节点,返回1>,继续执行,直到栈为空且x为Null.

Preorder_tree_walk(x){

      stack S;

      while(x!=null || S.top != null){

               while(x!=null){

                         print x.key;

                         push(S,x);

                         x=x.left;

               }

               if(S.top!=null){

                         x=pop(S);

                         x=x.right;

               }

      }

}

2、中序遍历:据中序遍历的顺序,先左孩子,再根节点,再右孩子。

     1>如图第一个红色箭头所示,依次将当前节点及其所有左后代元素压入栈(图中1,2,3),直到左孩子为空,

     2>将栈顶元素x弹出并打印,把x的右孩子作为当前节点,返回1>执行;



Inorder_tree_walk(x){

    stack S;

    while(x!=null || S.top!=null){

            while(x!=null){

                     push(S,x);

                     x=x.left;

            }

            if(S.top!=null){

                     x=pop(S);

                     print x.key;

                     x=x.right;

            }

    }

}

3、后序遍历:次序为左——右——根

a、第一种方法:

     1>沿左子树一直往下走,并依次压入栈,直到左孩子节点为空,此时不能将栈顶元素出栈,因为右子树还没有遍历,

      2>如果栈顶元素curr右孩子为空或者右孩子已访问,则输出栈顶元素,并置栈顶元素为prev上一个访问节点,

否则,置当前元素curr为栈顶元素右孩子,返回1>执行,当其右孩子访问完时,该节点又出现在栈顶,此时该节点可以出栈。

     可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。

Postorder_tree_walk(curr){

      stack S;

      prev=null;//上一次访问节点

      while(curr!=null || S.top!=null){

              while(curr!=null){              //一直向左走,并压入栈,直到左孩子为空

                        push(S,curr);

                        curr=curr.left;

              }

              curr=S.top;

              if(curr.right==null || curr.right==prev){            //如果当前元素右孩子为空或者右孩子已访问,则访问当前节点

                        print curr.key;

                        prev = curr;

                        pop(S);

                        curr=null;

              }

              else   curr=curr.right;//否则访问右孩子

      }

}

b、第二种方法

     要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。

Postorder_tree_walk(x){

      stack S;

      curr;    //当前节点

      prev=null;//上一个访问节点

      push(S,x);

      while(S.top!=null){

                curr=S.top;

                if((curr.left==null &&curr.right==null) ||

                   (prev!=null && (prev==curr.left||prev==curr.right))){

                           print curr.key;

                           pop(S);

                           prev=curr;

                }

                else {

                           if(curr.left!=null)

                               push(S,curr.left);

                           if(curr.right!=null)

                               push(S,curr.right);

                }

      }

}

参考资料:

1>http://blog.csdn.net/hackbuteer1/article/details/6583988

2>http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html

0 0