leetcode-zgd-day14-144.94.145.二叉树的前中后序遍历

145 阅读2分钟

144.94.145.二叉树的前中后序遍历

递归做法:

递归做法三种遍历方式的区别只在于语句执行顺序,比较好理解这里不过多赘述。

 // 前序
 class Solution {
     public List<Integer> preorderTraversal(TreeNode root) {
         ArrayList<Integer> ans = new ArrayList<>();
         preorder(root,ans);
         return ans;
     }
     void preorder(TreeNode root, List<Integer> list){
         if(root == null){
             return;
         }
         // 先序: 中左右
         list.add(root.val);
         preorder(root.left, list);
         preorder(root.right, list);
     }
 }
 ​
 // 中序
 class Solution {
     public List<Integer> inorderTraversal(TreeNode root) {
         ArrayList<Integer> ans = new ArrayList<>();
         inorder(root,ans);
         return ans;
     }
     void inorder(TreeNode root, List<Integer> list){
         if(root == null){
             return;
         }
         // 中序遍历顺序 左中右
         inorder(root.left, list);
         list.add(root.val);
         inorder(root.right, list);
     }
 }
 ​
 // 后序
 class Solution {
     public List<Integer> postorderTraversal(TreeNode root) {
         ArrayList<Integer> ans = new ArrayList<>();
         postorder(root,ans);
         return ans;
     }
     void postorder(TreeNode root, List<Integer> list){
         if(root == null){
             return;
         }
         // 后序顺序 左右中
         postorder(root.left, list);
         postorder(root.right, list);
         list.add(root.val);
     }
 }

迭代做法:

迭代解法中前序遍历较为简单,后续遍历是使用前序遍历的巧解

中序遍历的迭代思想就是,将所有左孩子都放到栈中,在处理每一个栈中节点的时候,这个节点必定没有左孩子或者左孩子已经在之前处理过了。所以只需要先输出其本身,再处理其右节点即可。

 // 前序遍历
 class Solution {
     public List<Integer> preorderTraversal(TreeNode root) {
         ArrayList<Integer> arrayList = new ArrayList<>();
         if(root == null) return arrayList;
         Stack<TreeNode> stk = new Stack<>();
         stk.push(root);
          // 从根节点开始,从栈中拿出一个节点,将他放入栈,然后将他的右节点和左节点插入
         while(!stk.isEmpty()){
             TreeNode node = stk.peek();
             stk.pop();
             arrayList.add(node.val);
              // 必须先右后左,因为栈是先进后出
             if(node.right != null) stk.push(node.right);
             if(node.left != null) stk.push(node.left);
         }
         return arrayList;
     }
 }
 ​
 // 中序遍历
 class Solution {
     public List<Integer> inorderTraversal(TreeNode root) {
         ArrayList<Integer> arrayList = new ArrayList<>();
         Stack<TreeNode> stk = new Stack<>();
         TreeNode cur = root;
         while(cur != null || !stk.isEmpty()){
             // 中序遍历 左中右
             if(cur != null){ // 如果有左孩子,就一直往下走
                 stk.push(cur);
                 cur = cur.left;
             }else { // 没有左孩子了,就去栈中找没有处理过的左孩子节点
                 cur = stk.peek(); // 当前节点要么没有左孩子要么左孩子的节点已经处理过了
                 stk.pop();
                 arrayList.add(cur.val); // 左已经输出了,所以该输出中了
                 cur = cur.right; // 将右节点作为跟节点,继续迭代处理。
             }
         }
         return arrayList;
     }
 }
 ​
 // 后序遍历
 class Solution {
     public List<Integer> postorderTraversal(TreeNode root) {
         // 后序遍历是先序遍历的一种巧解,后序遍历 左右中 先序遍历 中左右
         // 先序遍历略微处理就是 中右左 在将结果反转,即是后续遍历
         ArrayList<Integer> arrayList = new ArrayList<>();
         if(root == null) return arrayList;
                 Stack<TreeNode> stk = new Stack<>();
         stk.push(root);
         while(!stk.isEmpty()){
             TreeNode cur = stk.peek();
             stk.pop();
             arrayList.add(cur.val);
             if(cur.left != null) stk.push(cur.left);
             if(cur.right != null) stk.push(cur.right);
         }
         Collections.reverse(arrayList);
         return arrayList;
     }
 }
 ​

统一迭代法:

不管是前序中序后序,都可以采用统一迭代法对其进行处理:

统一迭代法中的入栈顺序在代码中从下向上看,正是对应遍历方式的遍历顺序

前: 中左右 中: 左中右 后: 左右中

在中间节点再次入栈之后再插入一个null,表示下一次读到它就可以弹出了。

 // 前序
 class Solution {
     public List<Integer> preorderTraversal(TreeNode root) {
         ArrayList<Integer> arrayList = new ArrayList<>();
         if(root == null) return arrayList;
         Stack<TreeNode> stk = new Stack<>();
         stk.push(root);
         while(!stk.isEmpty()){
             TreeNode cur = stk.peek();
             if(cur != null){
                 stk.pop();
                 if(cur.right != null) stk.push(cur.right); // 右
                 if(cur.left != null) stk.push(cur.left); // 左
                 stk.push(cur); // 中
                 stk.push(null);
             }else{
                 stk.pop();
                 arrayList.add(stk.pop().val);
             }
         }
         return arrayList;
     }
 }
 ​
 // 中序
 class Solution {
     public List<Integer> inorderTraversal(TreeNode root) {
         ArrayList<Integer> arrayList = new ArrayList<>();
         if(root == null) return arrayList;
         Stack<TreeNode> stk = new Stack<>();
         stk.push(root);
         while(!stk.isEmpty()){
             TreeNode cur = stk.peek();
             if(cur != null){
                 stk.pop();
                 if(cur.right != null) stk.push(cur.right); // 右
                 stk.push(cur); // 中
                 stk.push(null);
                 if(cur.left != null) stk.push(cur.left); // 左
             }else{
                 stk.pop();
                 arrayList.add(stk.pop().val);
             }
         }
         return arrayList;
     }
 }
 ​
 // 后序
 class Solution {
     public List<Integer> postorderTraversal(TreeNode root) {
         ArrayList<Integer> arrayList = new ArrayList<>();
         if(root == null) return arrayList;
         Stack<TreeNode> stk = new Stack<>();
         stk.push(root);
         while(!stk.isEmpty()){
             TreeNode cur = stk.peek();
             if(cur != null){
                 stk.pop();
                 stk.push(cur); // 中
                 stk.push(null);
                 if(cur.right != null) stk.push(cur.right); // 右
                 if(cur.left != null) stk.push(cur.left); // 左
             }else{
                 stk.pop();
                 arrayList.add(stk.pop().val);
             }
         }
         return arrayList;
     }
 }