二叉树是每个结点最多有两个子树的树结构。遍历二叉树就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。而二叉树的遍历有三种遍历方法:先序遍历(Preorder Traversal),中序遍历(Inorder Traversal),后序遍历(Postorder Traversal)。

       设L、D、R分别表示左子树、根结点和右子树。则DLR(先根次序遍历),LDR(中根次序遍历),LRD(后根次序遍历)。

代码实现:

public class BinaryTreeNode{
       int value;
       BinaryTreeNode left;
       BinaryTreeNode right;

       public BinaryTreeNode(int data,BinaryTreeNode leftNode,BinaryTreeNode rightNode){
               this.value=data;
               this.left=leftNode;
               this.right=rightNode;
       }
}

采用递归实现遍历

public class Solution{
      //前序遍历 Preorder Traversal
      public static void preorderTraversal(BinaryTreeNode node){
            if(node!=null){
                   System.out.print(node.value);
                   preorderTraversal(node.left);
                   preorderTraversal(node.right);
            }
      }
   
      //中序遍历 Inorder Traversal
      public static void inorderTraversal(BinaryTreeNode node){
             if(node!=null){
                   inorderTraversal(node.left);
                   System.out.print(node.value);
                   inorderTraversal(node.right);
             }
      }

      //后序遍历 Postorder Traversal
      public static void postorderTraversal(BinaryTreeNode node){
             if(node!=null){
                   postorderTraversal(node.left);
                   postorderTraversal(node.right);
                   System.out.print(node.value);
             }
      }

      public static void main(String[] args){
             BinaryTreeNode node4=new BinaryTreeNode (4,null,null);
             BinaryTreeNode node5=new BinaryTreeNode (5,null,null);
             BinaryTreeNode node6=new BinaryTreeNode (6,null,null);
             BinaryTreeNode node7=new BinaryTreeNode (7,null,null);
             BinaryTreeNode node2=new BinaryTreeNode (2,node4,node5);
             BinaryTreeNode node3=new BinaryTreeNode (3,node6,node7);
             BinaryTreeNode node1=new BinaryTreeNode (1,node2,node3);
             System.out.println("前序遍历");
             preorderTraversal(node1);
             System.out.println();
             System.out.println("中序遍历");
             inorderTraversal(node1);
             System.out.println();
             System.out.println("后序遍历");
             postorderTraversal(node1);
      }
}

采用非递归实现遍历(使用栈来保存需要返回后处理的结点)

前序遍历:

1)如果当前结点存在,则处理当前结点的值(先处理根结点的值),然后将当前结点入栈,当前结点指向左子结点,并对该左子结点(此时的当前结点)进行相同处理。重复1的操作。

2)当前结点不存在,当前结点指向栈顶元素,栈顶元素出栈,当前结点指向右子结点,并对该右子结点(此时的当前结点)进行相同的处理。重复1的操作。

代码实现:

public void preorderTraversal(BinaryTreeNode node){
       //定义一个栈,存放结点,栈顶元素是当前结点
       Stack stack=new Stack();
       BinaryTreeNode curNode=node;
       //当前结点不为null或栈不为空时,一直循环
       while(curNode!=null||!stack.empty()){
               //该结点不为null
               if(curNode!=null){
                     //显示该结点的值
                     System.out.print(curNode.value);
                    //将该结点入栈
                     stack.push(curNode);
                    //将当前结点指向下一个左子结点
                     curNode=curNode.left;
               }else{
                    //如果curNode==null 则从stack中获取栈顶元素,即当前结点
                    curNode=(BinaryTreeNode)stack.peek();
                   //当前结点出栈
                    stack.pop();
                   //将当前结点指向下一个右子结点
                    curNode=curNode.right;
               }
       }
}

中序遍历:

1)如果当前结点存在,则将当前结点入栈,指向左子结点,并将该左子结点(此时的当前结点)进行相同处理。重复1的操作。

2)如果当前结点不存在,当前结点指向栈顶元素,栈顶元素出栈,处理当前结点值(因为左子结点不存在或者已经处理完了),指向右子结点,并对该右子结点(此时的当前结点)进行相同处理。重复1的操作。

代码实现:

public void inorderTraversal(BinaryTreeNode node){
        //定义一个栈,存放结点
        Stack stack=new Stack();
        BinaryTreeNode curNode=node;
        //如果curNode不为null或者stack不为空,则一直循环
        while(curNode!=null||!stack.empty()){
               if(curNode!=null){
                    //将该结点入栈
                     stack.push(curNode);
                    //将当前结点指向下一左子结点
                     curNode=curNode.left();
               }else{
                     //当前结点为null,则将当前结点指向栈顶元素
                     curNode=(BinaryTreeNode)stack.peek();
                    //处理当前结点的值
                     System.out.print(curNode.value);
                    //出栈
                     statck.pop();
                    //将当前结点指向下一右子结点
                    curNode=curNode.right;
               }
        }
}

后序遍历:

1)如果当前结点存在,则当前结点入栈,当前结点指向下一左子结点,标识0入栈,并对该左子结点(此时的当前结点)进行相同处理。重复1的操作。

2)当前结点不存在,当前结点指向栈顶元素,栈顶元素出栈,标识位出栈。如果标识位为0,则当前结点入栈,指向右子结点,标识1入栈。并对该右子结点(此时的当前结点)进行步骤1的处理,重复1的操作;如果标识位为1,则说明处理过了左右子结点,此时处理当前结点的value,继续对栈顶元素进行相同处理(当前结点置空,重复步骤2,重复2的操作)。

代码实现:

public void postorderTraversal(BinaryTreeNode){
       //保存需要返回处理的结点
       Stack sTree=new Stack();
       //保存返回的路径标识
       Stack sFlag=new Stack();
       BinaryTreeNode curNode=node;
       
        while(curNode!=null||!sTree.empty()){
               if(curNode!=null){
                     //当前结点入栈
                     sTree.push(curNode);
                    //下一步处理左子结点,返回时从左子结点返回,保存标识为0
                     sFlag.push(0);
                    //指向左子结点,进行步骤1操作
                     curNode=curNode.left;
               }else{
                     //当前结点指向栈顶元素
                     curNode=(BinaryTreeNode)sTree.peek();
                     //结点出栈
                     sTree.pop();
                     //获取返回路径
                     int flag=((Integer)sFlag.peek()).intValue();
                    //标识出栈
                     sFlag.pop();
         
                     if(flag==0){
                           //从左子结点返回,此时应该处理右子结点 
                           //当前结点入栈
                           sTree.push(curNode);
                           //下一步处理右子结点,保存标识1
                           sFlag.push(1);
                           //指向右子结点,进行步骤1的处理
                           curNode=curNode.right;
                     }else{
                           //从右子结点返回,此时应该处理根结点的值
                           System.out.print(curNode.value);
                          //为了进行步骤2,根据循环逻辑,这里将当前结点置空
                           curNode=null;
                     }
               }
         }       
}

 

 posted on 2018-10-18 17:15  会飞的金鱼  阅读(128)  评论(0)    收藏  举报