首页 > 其他分享 >二叉树的遍历大冒险

二叉树的遍历大冒险

时间:2023-08-21 22:23:02浏览次数:38  
标签:遍历 TreeNode null subRoot result 大冒险 root stack 二叉树

二叉树的遍历大冒险

〇、前言

01 文章内容

  • 一般提到二叉树的遍历,我们是在说
    • 前序遍历、中序遍历、后序遍历和层序遍历
  • 或者说三序遍历+层序遍历,毕竟三序和层序的遍历逻辑相差比较大
  • 下面讨论三序遍历的递归方法、非递归方法和非递归迭代的统一方法
  • 然后再讨论一下层序的一般迭代方法(通过队列)

02 力扣网址

一、前序遍历

01 递归实现

  • 递归的基本逻辑是比较简单的,但是注意根据题目的需求不同,实现方式是存在差异的
  • 如果题目要求主函数返回一个结果列表,那么就要构造一个辅助函数来帮助实现
  • 如果题目只要求函数打印前序遍历的序列,那么一个函数就足够了

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root,result);
    return result;

}
void preorderTraversalHelper(TreeNode root,List<Integer> result){
    if(root == null) return;
    result.add(root.val);
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    return;
}

(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversalHelper(TreeNode root){
    if(root == null) return;
    result.add(root.val);
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    return;
}

(3) 纯真打印版本

void preorderTraversal(TreeNode root){
    if(root == null) return;
    System.out.print(root.val);
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    return;
}

02 非递归实现

(1) 一般迭代法


(2) 统一迭代法

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root); //将根结点入栈
    while(!stack.isEmpty()){
        subRoot = stack.pop(); //弹出获取栈顶结点
        if(subRoot != null){
            //===右===
            if(subRoot.right != null){
                // 添加右结点(空结点不入栈)
                stack.push(subRoot.right);
            }
            //===左===
            if(subRoot.left != null){
                // 添加左节点(空结点不入栈)
                stack.push(subRoot.left);
            }
            //===中===
            stack.push(subRoot); // 添加中结点
            stack.push(null); // 中结点访问过,但是还没有处理,加入空结点做为标记。
        }else{ // 只有遇到空结点的时候,才将下一个结点放进结果集
            result.add(stack.pop().val); //重新取出栈中元素,加入到结果集
        }
    }
    return result;
}

二、中序遍历

01 递归实现

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root,result);
    return result;

}
void preorderTraversalHelper(TreeNode root,List<Integer> result){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    result.add(root.val);
    inorderTraversalHelper(root.right,result);
    return;
}

(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversalHelper(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    result.add(root.val);
    inorderTraversalHelper(root.right,result);
    return;
}

(3) 纯真打印版本

void preorderTraversal(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    System.out.print(root.val);
    inorderTraversalHelper(root.right,result);
    return;
}

02 非递归实现

(1) 一般迭代法

void inOrderNonRecur(){
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = root;
    if (subRoot != null) {
        while (!stack.isEmpty() || subRoot != null) {
            if (subRoot != null) {
                stack.push(subRoot);
                subRoot = subRoot.left;
            } else {
                subRoot = stack.pop();
                System.out.print("【"+subRoot.val+"】");
                subRoot = subRoot.right;
            }
        }
    }
}

(2) 统一迭代法

带注释版本

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root);
    while (!stack.isEmpty()) {
        subRoot = stack.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中
        if (subRoot != null) {
            //===右===
            if(subRoot.right != null){
                // 添加右节点(空节点不入栈)
                stack.push(subRoot.right);
            }
            //===中===
            stack.push(subRoot); // 添加中节点
            stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
            //===左===
            if(subRoot.left != null){
                // 添加左节点(空节点不入栈)
                stack.push(subRoot.left);
            }
        } else { // 只有遇到空节点的时候,才将下一个节点放进结果集
            result.add(stack.pop().val); // 加入到结果集
        }
    }
    return result;
}

无注释版本

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root);
    while (!stack.isEmpty()) {
        subRoot = stack.pop();
        if (subRoot != null) {
            if(subRoot.right != null) stack.push(subRoot.right);
            stack.push(subRoot);
            stack.push(null);
            if(subRoot.left != null) stack.push(subRoot.left);
        } else {
            result.add(stack.pop().val);
        }
    }
    return result;
}

三、后序遍历

01 递归实现

(1) 返回列表版本1

返回列表版本:辅助函数携带结果列表

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root,result);
    return result;

}
void preorderTraversalHelper(TreeNode root,List<Integer> result){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    result.add(root.val);
    return;
}

(2) 返回列表版本2

返回列表版本:设置全局变量

List<Integer> result = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
    inorderTraversalHelper(root,result);
    return result;
}
void preorderTraversalHelper(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    result.add(root.val);
    return;
}

(3) 纯真打印版本

void preorderTraversal(TreeNode root){
    if(root == null) return;
    inorderTraversalHelper(root.left,result);
    inorderTraversalHelper(root.right,result);
    System.out.print(root.val);
    return;
}

02 非递归实现

(1) 一般迭代法

public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    if (root != null) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root);
        TreeNode subRoot = null;
        while (!stack.isEmpty()) {
            subRoot = stack.peek();
            if (subRoot.left != null && root != subRoot.left && root != subRoot.right) {
                stack.push(subRoot.left);
            } else if (subRoot.right != null && root != subRoot.right) {
                stack.push(subRoot.right);
            } else {
                result.add(stack.pop().val);
                root = subRoot;
            }
        }
    }
    return result;
}

(2) 双栈迭代法

public List<Integer> postOrderNonRecurByTwoStack(){
    List<Integer> result = new ArrayList<>();
    TreeNode subRoot = root;
    if (subRoot != null) {
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        s1.push(subRoot);
        while (!s1.isEmpty()) {
            subRoot = s1.pop();
            s2.push(subRoot);
            if (subRoot.left != null) {
                s1.push(subRoot.left);
            }
            if (subRoot.right != null) {
                s1.push(subRoot.right);
            }
        }
        while (!s2.isEmpty()) {
            result.add(s2.pop().val);
        }
    }
}

(3) 统一迭代法

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> result = new LinkedList<>();
    Stack<TreeNode> stack = new Stack<>();
    TreeNode subRoot = new TreeNode();

    if (root != null) stack.push(root); //将根结点入栈
    while(!stack.isEmpty()){
        subRoot = stack.pop(); //弹出获取栈顶结点
        if(subRoot != null){
            //===中===
            stack.push(subRoot); // 添加中结点
            stack.push(null); // 中结点访问过,但是还没有处理,加入空结点做为标记。
            //===右===
            if(subRoot.right != null){
                // 添加右结点(空结点不入栈)
                stack.push(subRoot.right);
            }
            //===左===
            if(subRoot.left != null){
                // 添加左节点(空结点不入栈)
                stack.push(subRoot.left);
            }
        }else{ // 只有遇到空结点的时候,才将下一个结点放进结果集
            result.add(stack.pop().val); //重新取出栈中元素,加入到结果集
        }
    }
    return result;
}

四、层序遍历

01 不分层输出

class Solution {
    public int[] levelOrder(TreeNode root) {
        //if(root == null) return new int[]{};
        ArrayList<Integer> result = new ArrayList<Integer>();
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        TreeNode subRoot = new TreeNode();
        
        if(root != null) queue.offer(root);
        while(!queue.isEmpty()){
            subRoot = queue.poll();
            result.add(subRoot.val);
            if(subRoot.left != null) queue.add(subRoot.left);
            if(subRoot.right != null) queue.add(subRoot.right);
        }
        
        int[] dest = new int[result.size()];
        for(int i = 0 ; i < result.size() ; i++){
            dest[i] = result.get(i);
        }
        return dest;
    }
}

02 分层输出

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> ret = new ArrayList<List<Integer>>();
    if (root == null) {
        return ret;
    }

    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        List<Integer> level = new ArrayList<Integer>();
        int currentLevelSize = queue.size();
        for (int i = 1; i <= currentLevelSize; ++i) {
            TreeNode node = queue.poll();
            level.add(node.val);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        ret.add(level);
    }

    return ret;
}

标签:遍历,TreeNode,null,subRoot,result,大冒险,root,stack,二叉树
From: https://www.cnblogs.com/Ding1fun/p/17647236.html

相关文章

  • C++遍历TypeList(可变模板参数)的简单办法
        这里例举了两种方案,一种是基于C++17的constexpr,实现起来更精简。另外一种使用传统的方式,C++11就可以用了。    另外C++11的方案也是一种计算不定参数模板参数个数的方法。#include<iostream>#include<string>//inC++17#if((defined(_MSVC_LANG)......
  • 剑指 Offer 33. 二叉搜索树的后序遍历序列(中等)
    题目:结合以下图理解该方法classSolution{//本题要点:二叉搜索树性质:根节点一定大于所有左子树,一定小于所有右子树public:booltraversal(vector<int>&postorder,intl,intr){//l和r分别为当前树的左右边界if(l>=r)returntrue;int......
  • 代码随想录算法训练营第二十一天| 530.二叉搜索树的最小绝对差 501.二叉搜索树中的
     530.二叉搜索树的最小绝对差   卡哥建议:需要领悟一下二叉树遍历上双指针操作,优先掌握递归   题目链接/文章讲解:https://programmercarl.com/0530.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E7%BB%9D%E5%AF%B9%E5%B7%AE.html ......
  • 代码随想录算法训练营第二十天| 654.最大二叉树 617.合并二叉树 700.二叉搜索树
      654.最大二叉树    卡哥建议:又是构造二叉树,昨天大家刚刚做完 中序后序确定二叉树,今天做这个 应该会容易一些, 先看视频,好好体会一下 为什么构造二叉树都是 前序遍历    题目链接/文章讲解:https://programmercarl.com/0654.%E6%9C%80%E5%A4%A7%E4%BA%8C%E5......
  • 【二叉树前沿篇】树
    1树的概念树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。树有一个特殊的结点,称为根结点,根节点没有前驱结点。除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……......
  • 求先序,中序,后序等遍历中第k个结点的值
    代码自己想的,23年8月21没有仔细看王道书上的代码和自己写的有什么区别,测试应该是对的。但是如果k的值大于结点个数没有做判断#include<stdio.h>#include<stdlib.h>typedefstructTNode{intdata;structTNode*lchild,*rchild;}TreeNode,*Tree;voidCreate......
  • #yyds干货盘点# LeetCode程序员面试金典:完全二叉树的节点个数
    题目:给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。 示例1:输入:r......
  • 【二叉树前沿篇】树
    1树的概念树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。树有一个特殊的结点,称为根结点,根节点没有前驱结点。除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……......
  • TWCMS实现遍历所有频道及下面的分类
    $cate_arrs=$run->category->find_fetch();foreach($cate_arrsas$v){if($v['upid']==0){$v['flist']=$run->category->find_fetch(array('upid'=>$v['cid']));$parrs[]=$v; } } //hookkp_block_listeac......
  • 1.8.21二维数组右上左下遍历
    1.题目描述给定一个row行col列的整数数组array,要求从array[0][0]元素开始,按从左上到右下的对角线顺序遍历整个数组。输入输入的第一行上有两个整数,依次为row和col。余下有row行,每行包含col个整数,构成一个二维整数数组。(注:输入的row和col保证0<row<100,0<col<100)输......