训练营1004|二叉树(递归遍历|迭代遍历|统一迭代)

1.二叉树基础理论

 二叉搜索树

 二叉搜索树是有数值的了,二叉搜索树是一个有序树

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树

 平衡二叉搜索树

平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

 二叉树存储方式

 二叉树可以链式存储,也可以顺序存储。

那么链式存储方式就用指针, 顺序存储的方式就是用数组。顺序存储的元素在内存是连续分布的,而链式存储则是通过指针把分布在散落在各个地址的节点串联一起。

用数组来存储二叉树如何遍历的呢?

如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。

 2.二叉树递归遍历

 144.二叉树的前序遍历

 根据递归序,根左右

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode() {
    }

    TreeNode(int val) {
        this.val = val;
    }

    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

class Solution {
    /**
     * 二叉树的前序遍历---->根左右(遍历)
     *
     * @param root
     * @return
     */
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        process(root, ans);
        return ans;
    }

    /**
     * 递归---->递归序
     *
     * @param root
     * @param ans
     */
    public void process(TreeNode root, List<Integer> ans) {
        if (root == null) {
            return;
        }
        ans.add(root.val);
        process(root.left, ans);
        process(root.right, ans);
    }
}

 94.二叉树的中序遍历

class Solution {
    /**
     * 二叉树的中序遍历---->左根右(遍历)
     *
     * @param root
     * @return
     */
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        process(root, ans);
        return ans;
    }

    /**
     * 递归---->递归序
     *
     * @param root
     * @param ans
     */
    public void process(TreeNode root, List<Integer> ans) {
        if (root == null) {
            return;
        }
        process(root.left, ans);
        ans.add(root.val);
        process(root.right, ans);
    }
}

 145.二叉树的后序遍历 

class Solution {
    /**
     * 二叉树的后序遍历---->左右根(遍历)
     *
     * @param root
     * @return
     */
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        process(root, ans);
        return ans;
    }

    /**
     * 递归---->递归序
     *
     * @param root
     * @param ans
     */
    public void process(TreeNode root, List<Integer> ans) {
        if (root == null) {
            return;
        }
        process(root.left, ans);
        process(root.right, ans);
        ans.add(root.val);
    }
}

 3.二叉树的迭代遍历

 144.二叉树的前序遍历

前序用栈!!!

前序的顺序根---->左---->右。一直把根节点的左孩子压栈并且在结果集里面添加这些左孩子的值,直到压到空的时候,node变为现在栈顶弹出来的元素他自己本身作为根的时候已经压进去过了),然后指向其右孩子。(右孩子是否为空无所谓反正会进循环)

class Solution {
    /**
     * 二叉树前序遍历---->根左右,迭代法
     *
     * @param root
     * @return
     */
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode node = root;
        while (!stack.isEmpty() || node != null) {
            while (node != null) {
                stack.push(node);
                ans.add(node.val);
                node = node.left;
            }
            node = stack.pop();
            node = node.right;
        }
        return ans;
    }
}

  94.二叉树的中序遍历

 中序遍历:左------>根-------->右

 跟前序一样的模拟的是一个进栈和出栈,区别就是什么时候把栈里面的元素加入结果集呢?

前序是压栈的时候就加入,所以是个根先的状态,而中序,左孩子先遍历,所以弹出的时候加入结果集,因为他们都是左。

class Solution {
    /**
     * 二叉树的中序遍历----->左  根  右
     *
     * @param root
     * @return
     */
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }
        TreeNode node = root;
        Stack<TreeNode> stack = new Stack<>();
        while (!stack.isEmpty() || node != null) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            ans.add(node.val);
            node = node.right;
        }
        return ans;
    }
}

   *145.二叉树的后序遍历 

class Solution{
    public List<Integer> method1(TreeNode root) {
        List<Integer> ans=new LinkedList<>();
        Stack<TreeNode> stack=new Stack<>();
        TreeNode prev=null;
        //主要思想:
        //由于在某颗子树访问完成以后,接着就要回溯到其父节点去
        //因此可以用prev来记录访问历史,在回溯到父节点时,可以由此来判断,上一个访问的节点是否为右子树
        while(root!=null||!stack.isEmpty()){
            while(root!=null){
                stack.push(root);
                root=root.left;
            }
            //从栈中弹出的元素,左子树一定是访问完了的
            root=stack.pop();
            //现在需要确定的是是否有右子树,或者右子树是否访问过
            //如果没有右子树,或者右子树访问完了,也就是上一个访问的节点是右子节点时
            //说明可以访问当前节点
            if(root.right==null||prev==root.right){
                ans.add(root.val);
                //更新历史访问记录,这样回溯的时候父节点可以由此判断右子树是否访问完成
                prev=root;
                root=null;
            }else{
            //如果右子树没有被访问,那么将当前节点压栈,访问右子树
                stack.push(root);
                root=root.right;
            }
        }
        return ans;
    }
}

2022.10.22补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值