“非递归” 实现二叉树的“前序、中序、后序、层序”遍历

文章介绍了如何使用非递归方式实现二叉树的前序、后序、中序和层序遍历,主要利用栈和队列的数据结构。前序遍历和后序遍历通过调整压栈顺序实现,中序遍历则使用一个指针遍历并结合栈,而层序遍历则采用广度优先搜索(BFS)策略。
摘要由CSDN通过智能技术生成

目录

前言

一、前序遍历

二、后续遍历

三、中序遍历

四、层序遍历


前言


        相信学过或是了解过二叉树的朋友都知道,他的前序、中序、后序遍历使用递归法实现非常简单,那么如果使用非递归的方式来解,也就是使用迭代来解,你还能将他拿下么?实际上一点都不难,往下看~

一、前序遍历


前序遍历,就是按照 根结点->左节点->右节点 的顺序去访问,如果要使用非递归的方式去访问,我们就离不开一个重要的数据结构——“栈”(非常多适合用递归做的题用非递归的方式去做都是这样的思路),下面我们就来看看如何具体操作!

假设我们有二叉树的根节点 root,那么首先我们可以创建一个栈,将这个根节点放入栈中,接着,只要栈不为空,我们就进行循环,循环什么呢?每次 pop 出一个结点,只要这个结点右结点不为空就push压栈,接着左节点不为空就push压栈,这样循环,最后得到的就是线序遍历的结果。

Ps:因为是先序遍历,所以先从栈中弹出一个结点,接着压栈顺序是前右结点后左节点(原理:栈是先进后出的)。

力扣链接:144. 二叉树的前序遍历

根据这个链接,检验以下你是否能做对吧!

 代码如下:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack();
        stack.push(root);
        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);
            }
        }
        return list;
    }
}

二、后续遍历


后序遍历实际上只需要在前序遍历的代码的基础上稍作修改即可~ 原本前序遍历的遍历顺序为"根 -> 左 -> 右",那么我们可以这样变一下,更改入栈的顺序,改成"根 -> 右 -> 左",也就是如下这几行代码进行一个转换

接着在对得到的数组进行反转,那么遍历顺序就变成了 "左 -> 右 -> 根",这正好就是我们要的后序遍历!

力扣链接:145. 二叉树的后序遍历

根据这个链接,检验以下你是否能做对吧!

代码如下:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack();
        stack.push(root);
        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);
        return list;
    }
}

三、中序遍历


中序遍历的迭代法思路就和 前序后序 不一样了,因为中序遍历的遍历顺序与读取结点的 val 值的顺序不一样~ 实际上,我们可以用 栈 来记录结点,用一个 cur指针 来遍历!

具体的,我们可以使用一个 cur指针 先指向根节点,然后进行循环,循环什么呢?当 cur指针 不为空时,就让 cur指针 一值向左走,边走边用栈记录下结点值,当 cur指针 为空时,我们就可以从栈中弹出元素给 cur指针 ,接着让 cur 指针向右结点走,接着循环以上步骤,直到 cur == null 并且 栈为空为止。

力扣链接:94. 二叉树的中序遍历

根据这个链接,检验以下你是否能做对吧!

代码如下:

    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            if(cur != null) {
                //让 cur 一路向左走,如果当前遍历元素不为空就入栈
                stack.push(cur);
                cur = cur.left;
            } else {
                //若当前元素为空,说明左边走到头了,这时候就可以弹出元素
                cur = stack.pop();
                list.add(cur.val);
                cur = cur.right;
            }
        }
        return list;
    }

四、层序遍历


这里便是经典的 BFS,层序遍历便是从上到下获取到每一层的数据,再将每一层依次从左到右打印。具体的,我们可以使用一个队列,首先将根结点入栈,然后用一个 size 记录下当前行的有多少个结点,通过这个 size 我们便可以直到需要弹出这一行多少元素,每弹出一个元素,就检查他的左右孩子是否为空(层序遍历,先左后右,顺序不可以颠倒),不为空就继续放入栈中

力扣链接:94. 二叉树的中序遍历

根据这个链接,检验以下你是否能做对吧!

代码如下:

    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret = new ArrayList<>();
        if(root == null){
            return ret;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            //row为一行的数据
            List<Integer> row = new ArrayList<>();
            //确定一层的数据
            while(size > 0){
                TreeNode cur = queue.poll();
                row.add(cur.val);
                if(cur.left != null){
                    queue.offer(cur.left);
                }
                if(cur.right != null){
                    queue.offer(cur.right);
                }
                size--;
            }
            //添加一层的数据
            ret.add(row);
        }
        return ret;
    }

1. 创建二叉树根据给定的前序遍历结果,我们可以遵循这样的步骤: - 首前序遍历的第一个元素通常是根节点。 - 然后,在剩余的数据中找到该节点的左子树和右子树对应的前序列。左子树的前序列是当前节点开始到下一个节点之前的部分,右子树则是从当前节点后的部分开始。 - 使用递归的方式实现这个过程,直到遍历完所有数据。 ```python def create_binary_tree(preorder): if not preorder: return None root_val = preorder.pop(0) # 取出根节点 root = TreeNode(root_val) # 创建新的根节点 if len(preorder) > 0: index = inorder.index(root_val) # 找到根节点在中序遍历中的位置 left_subtree = create_binary_tree(preorder[:index]) # 递归构建左子树 right_subtree = create_binary_tree(preorder[index + 1:]) # 递归构建右子树 root.left = left_subtree root.right = right_subtree return root ``` 2. 二叉树遍历有多种方式: - **前序遍历** (递归/非递归): - 递归:`dfs_preorder(root)` - 非递归(栈):使用前驱节点存储信息,`build_preorder(root, stack=[])`,入栈root,然后访问节点并出栈处理左右子树。 - 非递归(栈):与前序类似,但是入栈节点后立即访问,之后再处理子树。 - **后序遍历** (递归/非递归): - 递归:`dfs_postorder(root)` - 非递归(堆栈):可以将前序遍历稍作调整,后访问节点。 - **层序遍历** (非递归): - 队列:用两个队列分别存储每一层的节点,入后出的原则完成遍历。 这里省略了具体的代码细节,因为它们需要完整的实现并且涉及大量辅助函数和节点类定义。 3. 计算叶子节点数和深度: - 叶子节点数:在遍历过程中,如果遇到None值,则说明到达了一个叶子节点,计数加一。 - 深度:可以从每个节点出发,使用递归或广度优搜索(BFS)算法计算。 ```python def count_leaves(node): if node is None: return 0 elif node.left is None and node.right is None: return 1 else: return count_leaves(node.left) + count_leaves(node.right) def tree_depth(node, depth=0): if node is None: return depth else: return max(tree_depth(node.left, depth+1), tree_depth(node.right, depth+1)) # 示例 root = ... # 创建好的二叉树 leaf_count = count_leaves(root) depth = tree_depth(root) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值