二叉树——144,94,145

今天开始学习二叉树相关内容。刚开始学习二叉树,就像学习数据结构一样,先学比较经典的二叉树的三种深度遍历方式,分别是前序遍历,中序遍历,以及后续遍历。我在学数据结构的时候,光学会了最简单的递归法遍历。今天在刷题的时候,学会了使用非递归法也就是迭代法来遍历。前中后序遍历,顾名思义,就是根节点的遍历的顺序。

LeetCode144.二叉树的前序遍历

二叉树的前序遍历

前序遍历,即根节点在最前面被遍历,遍历顺序为根左右

	public static void preOrder(TreeNode root,List<Integer> list){
        if (root==null){
            return;
        }
        list.add(root.val);
        preOrder(root.left,list);
        preOrder(root.right,list);
    }

    public static List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list=new ArrayList<>();
        preOrder(root,list);
        return list;
    }

使用递归法,按照leetcode的题目要求,需要使用两个函数解决问题。第一个函数preOrder,就是做了递归的操作,将二叉树按照根左右的顺序将其每一个节点遍历出来。在第二个函数中,按题目要求,将其加入列表中。递归操作就是,先遍历根节点,然后递归遍历其左子树,然后递归遍历其右子树。

递归法较为简单,接下来则是较为复杂的迭代法。

	public static void PreOrder2(TreeNode root,List<Integer> list) {
        Stack<TreeNode> stack = new Stack<>();
        if (root != null) {
            stack.push(root);
        } else {
            return;
        }
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            list.add(node.val);
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
    }

递归操作其本质也是使用了栈这种数据结构。所以在迭代法中,我们需要借助一个栈进行操作。首先,判断root是否为空,如果为空则说明该二叉树没有节点,直接返回空列表即可。否则,将root入栈。接着进入循环,如果栈中元素不为空,则说明该二叉树没有被遍历完,在这种条件下,应该不断循环进行遍历。首先将栈顶元素出栈,放入列表中,如果其右子节点存在,则将右子节点入栈,如果其左子节点存在,则将左子节点入栈。如此不断循环,则会按照根左右的顺序遍历每一个节点。其中有两点注意的地方,第一,这是先后两个if的判断,并不是一个if……else……这样的两个必选其一的判断。第二,这里的先后顺序,为什么前序遍历明明是根左右的顺序,但是先是右子节点入栈,之后才是左子节点入栈呢?这是因为栈这种数据结构的特点是,先入后出,如果我们要先左后右,那么入栈顺序则要相反,变成先右后左。

LeetCode94.二叉树的中序遍历

二叉树的中序遍历
中序遍历的顺序是左根右。所以使用递归法时,先递归遍历其左子树,然后遍历根节点,最后递归遍历右子树。

	public static void inOrder(TreeNode root,List<Integer> list){
        if (root==null){
            return;
        }
        inOrder(root.left,list);
        list.add(root.val);
        inOrder(root.right,list);
    }

    public static List<Integer> inorderTraversal(TreeNode root){
        List<Integer> list=new ArrayList<>();
        inOrder(root,list);
        return list;
    }

和前序遍历一样,为了实现LeetCode的题目要求,同样需要使用两个函数,一个负责递归遍历,另一个负责完成存入列表的操作。

接下来是中序遍历的迭代法。

	public static void InOrder2(TreeNode root,List<Integer> list){
        if(root==null){
            return;
        }
        Stack<TreeNode> stack =new Stack<>();
        TreeNode cur=root;
        while(cur!=null||!stack.isEmpty()){
            if (cur!=null){
                stack.push(cur);
                cur=cur.left;
            }else {
                cur=stack.pop();
                list.add(cur.val);
                cur=cur.right;
            }
        }
    }

首先判断根节点是否为空,如果为空说明该二叉树没有节点,返回空列表即可。我们同样需要借助栈这种数据结构,接着定义一个指针,先指向根节点。当该指针不为空,或者栈不为空时,都将进行不断循环,如果该指针不为空,则将其指向节点入栈,该指针指向此节点的左子节点。如果该指针为空,说明该指针上一个指向的元素没有左子节点或者右子节点,那么将其出栈,并将指针重新指向该节点,将该节点加入列表后,指向其右子节点。不断循环以上操作。中序遍历的操作和前序遍历的操作并不一样,需要多加区分。

LeetCode145.二叉树的后序遍历

二叉树的后续遍历
递归法和另外两层遍历相同思路,后序遍历的顺序是左右根。需要先递归遍历其左子树,再递归遍历其右子树,最后遍历根节点。

	public static void postOrder(TreeNode root,List<Integer> list){
        if (root==null){
            return;
        }
        postOrder(root.left,list);
        postOrder(root.right,list);
        list.add(root.val);
    }

    public static List<Integer> postorderTraversal(TreeNode root){
        List<Integer> list=new ArrayList<>();
        postOrder(root,list);
        return list;
    }

几乎一模一样的思路,来实现leetcode题目中的后序遍历的要求。

接下来我们看迭代法,后序遍历有一些技巧可以被利用。在前序遍历时,我们提到需要注意的点有,左右节点入栈顺序的问题,因为前序遍历需要先左后右,所以需要先右后左的入栈。但是如果我们颠倒其入栈顺序,则会变成根右左的顺序进行遍历,再将存好的列表进行反转,就会从根右左变成左右根的顺序,即后序遍历。

	public static void PostOrder2(TreeNode root, List<Integer> list) {
        Stack<TreeNode> stack = new Stack<>();
        if (root!=null){
            stack.push(root);
        }else {
            return;
        }
        while (!stack.isEmpty()){
            TreeNode node=stack.pop();
            list.add(node.val);
            if (node.left!=null){
                stack.push(node.left);
            }
            if (node.right!=null){
                stack.push(node.right);
            }
        }
        Collections.reverse(list);
    }
### 二叉树的数组存储实现 #### 使用数组存储二叉树的概念 二叉树可以通过数组来进行存储,这种方式特别适用于完全二叉树或接近完全二叉树的情况。对于一般的二叉树,如果存在缺失节点,则这些位置会在数组中用特定值(通常是`0`或其他特殊标记)填充[^1]。 #### 存储规则 当使用数组来表示一棵二叉树时,根节点位于索引为`1`的位置(假设基于1的索引)。对于任意给定的父节点i: - 左子节点存放在索引 `2*i` 处; - 右子节点存放在索引 `2*i + 1` 处; 这种映射关系使得通过简单的计算即可访问任何节点的孩子节点,从而简化了某些类型的遍历算法的设计和实现。 #### 示例代码展示如何构建并打印先序遍历的结果 下面是一个Python函数的例子,它接受一个列表作为输入参数,该列表代表按照上述规则编码后的二叉树,并返回其先序遍历序列: ```python def preorder_traversal(tree_array, index=1): result = [] if index >= len(tree_array) or tree_array[index] == 0: return [] # 访问当前节点 (Pre-order visit) result.append(tree_array[index]) # 遍历左子树 result.extend(preorder_traversal(tree_array, 2 * index)) # 遍历右子树 result.extend(preorder_traversal(tree_array, 2 * index + 1)) return result # 测试例子 test_cases = [ [None, 3, 1, 2], [None, 5, 1, 2, None, 4], [None, 13, 1, 2, 3, 4, None, 5, 6, 7, 8, None, None, 9, 10] ] for case in test_cases: print(' '.join(map(str, preorder_traversal(case)))) ``` 这段程序会输出与提供的测试案例相匹配的结果字符串,其中每个数字由单个空格分隔开来[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值