目录

一.结点的定义

二.递归法遍历二叉树

前序遍历

中序遍历

后序遍历

三.迭代(非递归)遍历二叉树

(1).迭代模拟法

前序遍历

中序遍历

后序遍历

(2).空指针标记法

前序遍历

中序遍历

后序遍历

(3).一些散的简便方法

前序遍历

后序遍历


一.结点的定义

首先这里先给出结点的定义,和leetcode树相关的题目都是这么定义结点的

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;}}

二.递归法遍历二叉树

前序遍历

遍历二叉树,将二叉树的前序序列存放到list中,对标LeetCode144题,94题,145题

class Solution {List<Integer> list = new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {if(root != null){list.add(root.val);  //这里表示的是对结点的操作preorderTraversal(root.left);preorderTraversal(root.right);}return list;}
}

中序遍历

class Solution {List<Integer> list = new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {if(root != null){preorderTraversal(root.left);list.add(root.val);  //这里表示的是对结点的操作preorderTraversal(root.right);}return list;}
}

后序遍历

class Solution {List<Integer> list = new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {if(root != null){preorderTraversal(root.left);preorderTraversal(root.right);list.add(root.val);  //这里表示的是对结点的操作}return list;}
}

三.迭代(非递归)遍历二叉树

(1).迭代模拟法

前序和中序的迭代模拟法比较简单,就相当于是把整个二叉树按顺序走了一遍,类似下面的图,前序遍历是第一次访问到结点的时候就输出,中序遍历是第二次访问到结点的时候输出。

这里注意用的是栈,node定义在外面,且根节点不需要先push进入栈,然后就是循环退出条件还要加一个node != null,和层序遍历还是不一样的。

前序遍历

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();if (root == null){return null;}Deque<TreeNode> stack = new LinkedList<>();TreeNode node = root;while(!stack.isEmpty() || node != null) {while (node != null) {stack.push(node);list.add(node.val);node = node.left;}node = stack.pop();node = node.right;  //这一步的时候会出现stack里面是空,但是node不是空的情况}return list;}
}

中序遍历

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();if (root == null){return list;}Deque<TreeNode> stack = new LinkedList<>();TreeNode node = root;while(!stack.isEmpty() || node != null){while (node != null){stack.push(node);node = node.left;}node = stack.pop();list.add(node.val);node = node.right;}return list;}
}

后序遍历

后序遍历的话,比前序和中序复杂一点。当一个结点pop出来以后,要判断当时是从哪边遍历上来的。

如果右子树为空,或者右子树之前已经遍历过了,那就是从右边上来的,保存当前node为prev表示已经遍历完了,然后把当前node置空,终止当前node的遍历。

如果右子树不为空而且没有被遍历过,那就是从左边上来的,往右走就行。这里必须再将当前结点push进去,因为当前结点后面还要访问一次。

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<Integer>();if (root == null) {return res;}Deque<TreeNode> stack = new LinkedList<>();TreeNode node = root;TreeNode prev = null;while (node != null || !stack.isEmpty()) {while (node != null) {stack.push(node);node = node.left;}node = stack.pop();if (node.right == null || node.right == prev) {//如果右子树为空,或者右子树之前已经遍历过了,那就是从右边上来的,保存当前node为prev表示已经遍历完了//然后把当前node置空,终止当前node的遍历res.add(node.val);prev = node;node = null;} else {  //如果右子树不为空而且没有被遍历过,那就是从左边上来的,往右走就行stack.push(node);  //这里必须再将当前结点push进去,因为当前结点后面还要访问一次node = node.right;}}return res;}
}

(2).空指针标记法

这种空指针标记法比较通用,思路也比较简单。简单来说就是利用空指针进行标记,以便于可以访问一个结点多次,第二次访问结点的时候再进行一些操作。

注意点:

  1. 这里用的是栈不是队列。所以入栈的时候要先入右子树,再入左子树。相当于是模拟了栈的执行。
  2. 取结点的时候用的是peek,要先判断这个结点是不是null结点,不能直接pop出去。如果是null结点,那就表示需要将当前结点pop出来了,先pop出空结点,再取元素,最后再pop。
  3. 还是要注意这里是栈,先进后出,如果是前序的话,是先入右子树,再入左子树,最后入根结点,这样出栈的时候就是根左右,也就是对应的前序序列。

前序遍历

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> st = new Stack<>();if (root != null) st.push(root);while (!st.empty()) {TreeNode node = st.peek();if (node != null) {st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)st.push(node);                          // 添加中节点st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。} else { // 只有遇到空节点的时候,才将下一个节点放进结果集st.pop();           // 将空节点弹出node = st.peek();    // 重新取出栈中元素st.pop();result.add(node.val); // 加入到结果集}}return result;}
}

中序遍历

class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> st = new Stack<>();if (root != null) st.push(root);while (!st.empty()) {TreeNode node = st.peek();if (node != null) {st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)st.push(node);                          // 添加中节点st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)} else { // 只有遇到空节点的时候,才将下一个节点放进结果集st.pop();           // 将空节点弹出node = st.peek();    // 重新取出栈中元素st.pop();result.add(node.val); // 加入到结果集}}return result;}
}

后序遍历

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> st = new Stack<>();if (root != null) st.push(root);while (!st.empty()) {TreeNode node = st.peek();if (node != null) {st.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中st.push(node);                          // 添加中节点st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)         } else { // 只有遇到空节点的时候,才将下一个节点放进结果集st.pop();           // 将空节点弹出node = st.peek();    // 重新取出栈中元素st.pop();result.add(node.val); // 加入到结果集}}return result;}
}

(3).一些散的简便方法

前序遍历

前序遍历的标记法可以不需要这么麻烦

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new LinkedList<>();Stack<TreeNode> st = new Stack<>();if (root != null) st.push(root);while (!st.empty()) {TreeNode node = st.pop();result.add(node.val);if (node.right!=null) st.push(node.right);  // 添加右节点(空节点不入栈)if (node.left!=null) st.push(node.left);    // 添加左节点(空节点不入栈)}return result;}
}

后序遍历

也可以使用set来进行标记,第一次访问到结点把结点的右左子树入栈,第二次访问再对该结点进行操作。

class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> res = new ArrayList<Integer>();if (root == null) {return res;}Deque<TreeNode> stack = new LinkedList<>();Set<TreeNode> set = new HashSet<>();stack.push(root);while (!stack.isEmpty()){TreeNode node = stack.peek();if(!set.contains(node)){set.add(node);if (node.right != null){stack.push(node.right);}if (node.left != null){stack.push(node.left);}}else {res.add(node.val);stack.pop();}}return res;}
}

Java~二叉树的前中后序遍历的几种方式(递归法,迭代法,标记法等)相关推荐

  1. Java二叉树的前中后序遍历

    Java二叉树的前中后序遍历 1.前序遍历 1.1前序遍历概念 1.2前序遍历习题 2.中序遍历 2.1中序遍历概念 2.2中序遍历习题 3.后续遍历 3.1后序遍历概念 3.2后序遍历习题 大家好, ...

  2. 二叉树N叉数的前中后序遍历总结,python实现递归法和迭代法

    关于二叉树的前序遍历(preoder).中序遍历(inorder)和后序遍历(postorder),实际上只需要记住:左子节点一定在右子节点的左边(左右),所谓前中后序遍历就是根节点的位置不同,前序是 ...

  3. 二叉树的前,中,后序遍历(思路分析) [Java][数据结构]

    二叉树的前,中,后序遍历(思路分析) 前序遍历: 先输出父节点, 再遍历左子树和右子树 中序遍历: 先遍历左子树, 再输出父节点,再遍历右子树 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点 ...

  4. 数据结构之二叉树的前中后序遍历以及层序遍历

    学习目标:读完这篇博客搞定二叉树的前中后序以及层序遍历 首先:你应该明白什么是二叉树,下面这幅图就是一个完全二叉树 其实所谓的二叉树就是一个节点有小于等于二个分支的树,可以没有分支,可以有1条分支,可 ...

  5. 数据结构与算法(java):树-二叉树(二叉查找树(BST)、线索化二叉树、哈夫曼树、平衡二叉树【AVL】、二叉树的前中后序遍历)

    二叉树 1.定义 二叉树 就是度不超过2的树(每个结点最多只有两个子结点).如图 2.特殊二叉树 满二叉树 当二叉树的每一个层的结点树都达到最大值,则这个二叉树就是满二叉树. 完全二叉树 叶结点只能出 ...

  6. 二叉树的前中后序遍历之迭代法(非统一风格迭代方式)

    文章目录 前言 一.前序遍历(迭代法) 二.中序遍历(迭代法) 三.后序遍历(迭代法) 总结 前言 「递归的实现就是:每一次递归调用都会把函数的局部变量.参数值和返回地址等压入调用栈中」,然后递归返回 ...

  7. 二叉树的前中后序遍历(栈)(C++)

    二叉树的遍历是很基础的东西,用递归是很简洁明了的写法,但是栈的写法也可以了解一下 #include<vector> #include<stack> struct TreeNod ...

  8. 二叉树的前中后序遍历(考试常考)

    二叉树遍历的概念 二叉树的遍历是按某种规则对二叉树的每个节点均只被访问一次,根据根节点访问位置的不同分为三种:先序遍历(根左右).中序遍历(左根右).后序遍历(左右根).         由于树是通过 ...

  9. 【Java数据结构】二叉树的前中后序遍历(递归和非递归)

    二叉树的遍历 递归做法 前序遍历 中序遍历 后序遍历 非递归 前序遍历 中序遍历 后序遍历 二叉树遍历是二叉树的一种重要操作 必须要掌握 二叉树的遍历可以用递归和非递归两种做法来实现 递归做法 前序遍 ...

最新文章

  1. 温水里的程序员,技术将淘汰一切。
  2. php 代码规范 工具,PHP工具篇:PHPStorm IDE使用CodeSniffer代码规范化管理
  3. Java vs Big data 哪种编程语言更好?
  4. 223. Rectangle Area
  5. 在Tomcat上跑东西时遇到的对我这样新手来说很难找到的问题
  6. C# MongoDB简单增删改查使用
  7. 理论基础 —— 排序 —— 快速排序
  8. html canvas绘制网格,canvas(七)绘制网格和坐标轴
  9. 语音识别的原理_语音识别原理_语音识别原理框图 - 云+社区 - 腾讯云
  10. TC软件概要设计文档(手机群控)
  11. D盘或者E盘根目录出现msdia80.dll文件的解决方法
  12. 微信小微商户申请入驻接口PHP示例
  13. RSS阅读器FeedDemon使用方法
  14. HTML5+CSS期末大作业:运动体育网站设计主题——体育铅球(5页)带注册 期末作业HTML代码 学生网页课程设计期末作业下载 web网页设计制作成品...
  15. 辉芒微IO单片机FT60F11F-MRB
  16. 李亚涛:python判断日志中的IP是否为百度蜘蛛
  17. 在线旅游市场分析2014年数据
  18. 坐标转换软件OpenCoord
  19. python读取.stl文件(以及转换为obj方法)
  20. 纯CSS实现目录自动编号

热门文章

  1. 电脑里的记事本文件永久删除怎么办
  2. 信号与系统陈后金matlab,信号与系统(陈后金)_MATLAB.ppt
  3. 信息通信行业政企业务主要发展方向探索
  4. P图片放大不失真方法
  5. maven项目打包报错Failed to execute goal org.apache.maven.plugins:maven-install-plugin:2.4:install (default
  6. 【全栈计划 —— 编程语言之C#】 C# 实现双人飞行棋小游戏
  7. DCDC电源干扰13.56M射频问题调研
  8. 关于MySql 5.6 'localhost' (10061)问题
  9. LINUX安装kafka步骤
  10. 取色器(Snipaste) 截图 贴图 取色