二叉树的遍历

102 阅读3分钟

二叉树遍历:访问树所有结点的过程叫做树遍历,并且在遍历过程中,每个结点只能被处理一次。遍历的目标是按照某种特定顺序访问树的所有结点。

遍历的分类(D表示当前结点L表示当前结点的左侧结点R表示当前结点的右侧结点):

  • 前序遍历(DLR)
  • 中序遍历(LDR)
  • 后序遍历(LRD)
  • 层序遍历:这种遍历方式不需要依赖顺序,是从图的广度优先遍历方法启发而来。

image-20220127110715706

前序遍历

概念:表示的是先访问中间结点,然后是该中间结点的左子结点,完成后再访问该中间结点的右子结点。因此根据这条规则可以得到上图的访问顺序是A-B-D-E-C-F-G

  • 访问根结点;
  • 按照前序遍历方式遍历左子树;
  • 然后按照前序遍历方式遍历右子树。

代码实现

 void PreOrder(BinaryTreeNode root){
   
     if(root != null){
       System.out.println(root.getData);
       PreOrder(root.getLeft());
       PreOrder(root.getRight());
     }
 }

时间复杂度O(n),空间复杂度O(n)。

非递归前序遍历

这里采用的非递归的方式需要实现前序遍历,需要引入操作。

也就是先操作根结点,然后操作左子树,判断该左子树是否还有子树,没有则操作根结点的右子树,如果有则继续操作该左子树的树,并将已经操作的结点存放在栈中进行保存。

代码实现:

 void PreOrederNonRecursive(BinaryTreeNode root){
   if(root == null){
     return null;
   }
   LLStack s = new LLStack();
   while(true){
     while(root != null){
       System.out.println(root.getData());
       S.push(root);
       root = root.getLeft();
     }
     if(S.isEmpty()){
       break;
     }
     root = (BinaryTreeNode)S.pop();
     root = root.getRight();
   }
   return;
 }

时间复杂度O(n),空间复杂度O(n)。

中序遍历

概念:已知前序遍历的情况下就比较好理解,是在确定了根结点后,先判断该根结点是否有左子树,如果没有则先操作根结点,然后再操作右子树。如果具有左子树,则先操作左子树,然后根结点,再右子树。上图访问顺序为D-B-E-A-F-C-G。

代码实现:

 void InOrder(BinaryTreeNode root){
   
     if(root != null){
       InOrder(root.getLeft());
       System.out.println(root.getData());
       InOrder.(root.getRight());
     }
 }

时间复杂度O(n),空间复杂度O(n)。

非递归中序遍历

同样这里也是采用栈进行数据的存取操作。

代码实现:

 void InOrderNonRecursive(BinaryTreeNode root){
   
   if(root == null){
     return null;
   }
   LLStack s = new LLStack();
   While(true){
     While(root != null){
       S.push(root);
       root = root.getLeft();
     }
     if(stack.isEmpty()){
       break;
     }
     root = (BinaryTreeNode)s.pop();
     System.out.println(root.getData());
     root = root.getRight();
   }
   return;
 }

时间复杂度O(n),空间复杂度O(n)。

后序遍历

概念:上图访问顺序为G-C-F-A-E-B-C。

代码实现:

 void PostOrder(BinaryTreeNode root){
   
     if(root != null){
       InOrder(root.getRight());
       System.out.println(root.getData());
       InOrder.(root.getLeft();
     }
 }

时间复杂度O(n),空间复杂度O(n)。

非递归实现

 void PostOrderNonRecursive(BinaryTreeNode root){
   
   if(root == null){
     return null;
   }
   LLStack s = new LLStack();
   While(true){
     While(root != null){
       S.push(root);
       root = root.getRight();
     }
     if(stack.isEmpty()){
       break;
     }
     root = (BinaryTreeNode)s.pop();
     System.out.println(root.getData());
     root = root.getLeft();
   }
   return;
 }

时间复杂度O(n),空间复杂度O(n)。

层序遍历

概念:

  • 访问根节点;
  • 在访问第i层的时候,将i+1层的结点按顺序保存在队列中;
  • 进入下一层并访问该层的所有结点;
  • 重复上述操作指导所有的结点都访问完成。

代码实现:

 void LevelOrder(BinaryTreeNode root){
   
   BinaryTreeNode temp;
   LLQueue q = new LLQueue();
   
   if(root == null){
     return null;
   }
   q.enQueue(root);
   While(!q.isEmpty()){
     
     temp = q.deQueue();
     //处理当前结点
     System.out.println(temp.getData());
     if(temp.getLeft()){
       q.enQueue(temp.getLeft());
     }
     if(temp.getRight()){
       q.enQueue(temp.getRight());
     }
     q.deleteQueue();
   }
 }

时间复杂度O(n),空间复杂度O(n)。