• 二叉树的中序遍历


    题目链接

    涉及知识:二叉树的遍历

    定义结点的结构:

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    

    1. 递归

    很经典的方法,没什么好解释的。

    class Solution {
        private List<Integer> list = new ArrayList<>();
    
        public List<Integer> inorderTraversal(TreeNode root) {
            inorderTra(root);
            return list;
        }
    
        public void inorderTra(TreeNode root){
            if(root == null){
                return;
            }
    
            inorderTra(root.left);
            list.add(root.val);
            inorderTra(root.right);
    
            return;
        }
    }
    

    时间复杂度:O(n),因为遍历的过程中,在每一个结点处进行的工作是常数时间,所以总的时间复杂度为O(n)

    空间复杂度:最坏情况下需要空间O(n),平均情况为O(log n)。

    为什么是常数时间:因为在遍历的过程中,每一个结点最多经过三次。

    空间复杂度和树的高度有关。

    2. 基于栈的遍历

    与递归类似,只不过是自己使用了栈代替递归。

    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> list = new ArrayList<>();
            Stack<TreeNode> tmp = new Stack<>();
            TreeNode cur = root;
    
            while(cur != null || !tmp.isEmpty()){
                while(cur != null){
                    tmp.push(cur);
                    cur = cur.left;
                }
    
                cur = tmp.pop();
                list.add(cur.val);
                cur = cur.right;
            }
            return list;
        }
    }
    

    时间复杂度:O(n)。

    空间复杂度:O(n)。

    3. 莫里斯遍历(线索二叉树)

    步骤:

    Step 1: 将当前节点 current 初始化为根节点

    Step 2: While current 不为空,

    若 current 没有左子节点

    • 将 current 添加到输出
    • 进入右子树,亦即, current = current.right

    否则

    • 在 current 的左子树中,令 current 成为最右侧节点的右子节点
    • 进入左子树,亦即,current = current.left

    例子:

          1
        /   
       2     3
      /    /
     4   5 6
    

    首先,1 是根节点,所以将 current 初始化为 1。1 有左子节点 2,current 的左子树是

         2
        / 
       4   5
    

    在此左子树中最右侧的节点是 5,于是将 current(1) 作为 5 的右子节点。令 current = cuurent.left (current = 2)。
    现在二叉树的形状为:

         2
        / 
       4   5
            
             1
              
               3
              /
             6
    

    对于 current(2),其左子节点为4,我们可以继续上述过程

        4
         
          2
           
            5
             
              1
               
                3
               /
              6
    

    由于 4 没有左子节点,添加 4 为输出,接着依次添加 2, 5, 1, 3 。节点 3 有左子节点 6,故重复以上过程。
    最终的结果是 [4,2,5,1,6,3]。

    代码:

    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> list = new ArrayList<>();
            TreeNode cur = root;
            TreeNode tmp = null;
    
            while(cur != null){
                //判断是否有左孩子
                if(cur.left == null){
                    list.add(cur.val);
                    cur = cur.right;
                }else{
                    tmp = cur.left;
    			
                    //找到当前结点左子树的最右孩子
                    while(tmp.right != null){
                        tmp = tmp.right;
                    }
    				
                    tmp.right = cur;     //将当前结点作为左子树的最右孩子
                    cur = cur.left;      //将当前结点更新为原节点的左孩子
                    tmp.right.left = null;   //将原结点的左孩子置为 null
                }
            }
            return list;
        }
    }
    

    时间复杂度:O(n),对于 n 个结点的二叉树有 n-1 条边,每一条边会经过两次,一次为定位结点,一次是寻找前驱结点。

    空间复杂度:O(n),只是因为使用了长度为 n 的数组,但在遍历的过程中并未重新申请新的空间。

    定位结点:更新当前根结点的过程

    寻找前驱结点:一直找最右孩子的过程

  • 相关阅读:
    【bzoj1176】[Balkan2007]Mokia
    【bzoj1503】[NOI2004]郁闷的出纳员
    C#设置和获取系统环境变量
    结伙创业指南及翻脸法则
    Unity3D_(游戏)卡牌03_选关界面
    Unity3D_(游戏)卡牌02_主菜单界面
    Unity3D_(游戏)卡牌01_启动屏界面
    Unity3D_(游戏)跳一跳超简单制作过程
    如何将项目托管到Github上
    Android_(游戏)打飞机06:后续
  • 原文地址:https://www.cnblogs.com/zcxhaha/p/11326697.html
Copyright © 2020-2023  润新知