【数据结构】二叉树遍历的非递归实现

前言:

本文使用栈以非递归的形式遍历整颗二叉树,我是通过数组模拟栈来实现的,如果对用数组模拟栈不太熟悉,你可以直接使用Stack类作为栈实现。

前序(先序)遍历:

要求: 二叉树节点的打印顺序为:中、左、右。

思路: 每次弹出一个节点就添加到结果集,如果节点的右孩子不为空,就让右孩子入栈、如果节点的左孩子不为空,就让左孩子进栈;栈会帮我们控制节点的弹出顺序。

题目链接: 144. 二叉树的前序遍历 - 力扣(LeetCode)

Code:

java 复制代码
class Solution {

    //题目规定节点个数在100以内
    public static int MAX = 101;
    public static TreeNode [] stack = new TreeNode[MAX];
    //栈中的元素个数
    public static int size;
    public List<Integer> preorderTraversal(TreeNode root) {
        //空树直接返回空集合
        if(root == null)
        return List.of();

        //一开始栈中没有元素
        size = 0;
        //头节点入栈
        stack[size++] = root;
        List<Integer> ans = new ArrayList<>();
        
        //只要栈不为空,一直弹出节点
        while(size > 0){
            TreeNode node = stack[--size];
            ans.add(node.val);
            
            //先让右孩子入栈、再让左孩子入栈
            //栈弹出节点时,左孩子先出栈、右孩子后出栈
            if(node.right != null)
            stack[size++] = node.right;

            if(node.left != null)
            stack[size++] = node.left;
        }
        return ans;
    }
}

中序遍历:

要求: 二叉树节点的打印顺序为:左、中、右。

思路: 指针p从根节点开始,不断向左子树遍历,遍历过程中将节点添加到栈中,当碰到空节点时,弹出此时处于栈顶的节点,将其添加到结果集中,并让指针p指向弹出节点的右节点,如果其右节点不为空,那么它会重复第一步的逻辑(不断向其左子树遍历),这样就能保证在处理完左树后,再去处理右树。

题目链接: 94. 二叉树的中序遍历 - 力扣(LeetCode)

Code:

java 复制代码
class Solution {

    public static int MAX = 101;

    public static TreeNode [] stack = new TreeNode[MAX];

    public static int size;
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root == null)
        return List.of();

        size = 0;
        List<Integer> ans = new ArrayList<>();
        TreeNode p = root;
        while(size > 0 || p != null){
            //只要指针p指向的节点不为null,就往其左子树遍历
            //并在遍历过程中,将节点添加到栈中
            if(p != null){
                stack[size++] = p;
                p = p.left;
            //当指针p指向的节点为null时,弹出栈顶节点
            //将栈顶节点添加到结果集
            //并让p指针指向栈顶节点的右子树
            }else{
                TreeNode node = stack[--size];
                ans.add(node.val);
                p = node.right;
            }
        }
        return ans;
    }
}

图解:

核心思想是: 每次将左树处理完后,再去处理右树。

后序遍历:

要求: 二叉树节点的打印顺序为:左、右、中。

思路: 前序遍历通过先添加右节点、再添加左节点实现中、左、右的遍历顺序,那我们先让左节点入栈,再让右节点入栈不就可以实现中、右、左的遍历顺序吗?最后再另起一个栈,将前一个栈的结果装到新启的栈中,就实现了左、右、中的遍历顺序。

题目链接145. 二叉树的后序遍历 - 力扣(LeetCode)

Code:

java 复制代码
class Solution {
    public static int MAX = 101;
    
    //栈1
    public static TreeNode [] stack = new TreeNode[MAX];
    
    //栈2
    public static TreeNode [] collect = new TreeNode[MAX];
    
    //栈1的元素个数
    public static int size1;
    
    //栈2的元素个数
    public static int size2;
    public List<Integer> postorderTraversal(TreeNode root) {
        //空树返回空集合
        if(root == null)
        return List.of();
        
        //初始化两个栈的大小
        size1 = size2 = 0;
        
        //让头结点进入栈1
        stack[size1++] = root;
        //遍历栈1
        while(size1 > 0){
            //弹出栈1中的元素
            TreeNode node = stack[--size1];
            
            //放入栈2中
            collect[size2++] = node;
            
            //如果左节点不为空,就放入栈1
            if(node.left != null)
            stack[size1++] = node.left;
            
            //如果右节点不为空,就放入栈2
            if(node.right != null)
            stack[size1++] = node.right;
        }
        List<Integer> ans = new ArrayList<>();

        //遍历栈2,不断弹出栈2中的元素添加到结果集
        while(size2 > 0){
            TreeNode node = collect[--size2];
            ans.add(node.val);
        }        
        return ans;
    }
}
相关推荐
didiplus8 分钟前
【趣学Python算法100例】百钱百鸡
python·算法·百钱百鸡
Monodye16 分钟前
【Java】网络编程:TCP_IP协议详解(IP协议数据报文及如何解决IPv4不够的状况)
java·网络·数据结构·算法·系统架构
pzx_00121 分钟前
【内积】内积计算公式及物理意义
数据结构·python·opencv·算法·线性回归
元气代码鼠23 分钟前
C语言程序设计(进阶)
c语言·开发语言·算法
十雾九晴丶1 小时前
攻防世界--->gametime
算法
Aurora_th2 小时前
树与图的深度优先遍历(dfs的图论中的应用)
c++·算法·深度优先·图论·dfs·树的直径
马剑威(威哥爱编程)3 小时前
除了递归算法,要如何优化实现文件搜索功能
java·开发语言·算法·递归算法·威哥爱编程·memoization
算法萌新——14 小时前
洛谷P2240——贪心算法
算法·贪心算法
湖北二师的咸鱼4 小时前
专题:二叉树递归遍历
算法·深度优先
重生之我要进大厂4 小时前
LeetCode 876
java·开发语言·数据结构·算法·leetcode