二叉树的先序、中序以及后序遍历(递归 && 非递归)
树节点定义:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
递归建立二叉树:
//递归建立二叉树
public static void BuildTree(TreeNode node, int data){
if(node == null){
node = new TreeNode(data);
} if(data <= node.val){
if(node.left == null){
node.left = new TreeNode(data);
}else{
BuildTree(node.left, data);
}
} if(data > node.val){
if(node.right == null){
node.right = new TreeNode(data);
}else{
BuildTree(node.right, data);
}
}
}
1、先序遍历
遍历方式:根节点-->左节点-->右节点
递归先序遍历:
//先序递归遍历二叉树
public static List<Integer> preTravese(TreeNode root,List<Integer> arr){
if(root == null)
return arr;
if(root != null){
arr.add(root.val);
arr = preTravese(root.left,arr);
arr = preTravese(root.right,arr);
}
return arr;
}
非递归遍历:
对于任意一个结点p
1)访问结点p,并将p入栈
2)将p变为p的左孩子结点,如果p的不为空,循环至 1); 否则弹出当前栈顶使用p接收,将p变为p的右孩子结点;
3)当p结点为null并且栈为空时,结束循环。
代码:
//非递归先序遍历
public static List<Integer> preorderTraversal(TreeNode root){
List<Integer> arr = new ArrayList<Integer>();
if(root == null){
return arr;
}
Stack<TreeNode> ts = new Stack<TreeNode>();
TreeNode ptr = root;
while( ptr != null || !ts.isEmpty()){
while(ptr != null){
arr.add(ptr.val);
ts.push(ptr);
ptr = ptr.left;
}
if( !ts.isEmpty()){
ptr = ts.pop();
ptr = ptr.right;
}
}
return arr;
}
2、中序遍历
遍历方式: 左子树-->根节点-->右子树
递归中序遍历:
//中序递归遍历二叉树
public static List<Integer> inTravese(TreeNode root,List<Integer> arr){
if(root == null)
return arr;
if(root != null){
arr = inTravese(root.left,arr);
arr.add(root.val);
arr = inTravese(root.right,arr);
}
return arr;
}
非递归中序遍历:
对于任意一个结点p
1)当结点不为null,将结点压栈;
2)将p更新为它的左孩子,如果左孩子不为空,循环至 1);否则弹出栈顶元素赋值给p,访问p结点,p更新为p的右孩子;
3)当p为null 并且栈为空时结束循环。
代码:
//中序非递归遍历
public static List<Integer> inorderTraversal(TreeNode root){
List<Integer> arr = new ArrayList<Integer>();
if(root == null){
return arr;
}
Stack<TreeNode> ts = new Stack<TreeNode>();
TreeNode ptr = root;
while( ptr != null || !ts.isEmpty() ){
while(ptr != null){
ts.push(ptr);
ptr = ptr.left;
}
if(!ts.isEmpty()){
ptr = ts.pop();
arr.add(ptr.val);
ptr = ptr.right;
}
}
return arr;
}
3、后序遍历
遍历方式:左子树-->右子树-->根节点
递归遍历:
//后序递归遍历二叉树
public static List<Integer> lastTravese(TreeNode root,List<Integer> arr){
if(root == null)
return arr;
if(root != null){
arr = lastTravese(root.left,arr);
arr = lastTravese(root.right,arr);
arr.add(root.val);
}
return arr;
}
非递归遍历:
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因为其右孩子还没有被访问。
接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。
这样就可以保证正确的访问顺序。
可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
代码:
首先新建一个类来记录结点是否是第一次弹栈:
//新建一个类,用来记录该结点是不是第一次弹栈
class NewTreeNode{
TreeNode ptr;
boolean isFirst;
public NewTreeNode(TreeNode ptr){
this.ptr = ptr;
this.isFirst = true;
}
}
非递归后序遍历二叉树:
//后序非递归遍历二叉树
public static List<Integer> lastTraverse(TreeNode root){
List<Integer> arr = new ArrayList<Integer>();
if(root == null){
return arr;
}
Stack<NewTreeNode> nts = new Stack<NewTreeNode>();
NewTreeNode nptr = null;
TreeNode ptr = root;
while( ptr!= null || !nts.isEmpty()){
while(ptr != null){
nptr = new NewTreeNode(ptr);
nts.push(nptr);
ptr = ptr.left;
} if(!nts.isEmpty()){
nptr = nts.pop();
if(nptr.isFirst){
nptr.isFirst = false;
nts.push(nptr);
ptr = nptr.ptr.right;
}else{
arr.add(nptr.ptr.val);
//ptr置为null,因为此时它的左右子树都已经访问完毕
ptr = null;
}
}
}
return arr;
} }
二叉树的先序、中序以及后序遍历(递归 && 非递归)的更多相关文章
- 递归/非递归----python深度遍历二叉树(前序遍历,中序遍历,后序遍历)
递归代码:递归实现很简单 '二叉树结点类' class TreeNode: def __init__(self, x): self.val = x self.left = None self.righ ...
- 二叉树的递归,非递归遍历(C++)
二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易 ...
- 【数据结构】——搜索二叉树的插入,查找和删除(递归&非递归)
一.搜索二叉树的插入,查找,删除 简单说说搜索二叉树概念: 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右 ...
- c/c++二叉树的创建与遍历(非递归遍历左右中,破坏树结构)
二叉树的创建与遍历(非递归遍历左右中,破坏树结构) 创建 二叉树的递归3种遍历方式: 1,先中心,再左树,再右树 2,先左树,再中心,再右树 3,先左树,再右树,再中心 二叉树的非递归4种遍历方式: ...
- C++二叉树前中后序遍历(递归&非递归)统一代码格式
统一下二叉树的代码格式,递归和非递归都统一格式,方便记忆管理. 三种递归格式: 前序遍历: void PreOrder(TreeNode* root, vector<int>&pa ...
- 已知二叉树的中序序列为DBGEAFC,后序序列为DGEBFCA,给出相应的二叉树
面对这种问题时我们该怎么解决? 今天写数据结构题.发现了一道总是碰见问题的题在这里我写了一种求解方法我自己称它为分层递归求解. 第一步通过观察我们知道后序遍历时最后一个是根节点A 在中序序列中A的左边 ...
- leetcode 236. 二叉树的最近公共祖先LCA(后序遍历,回溯)
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百 ...
- LeetCode 145 二叉树的后序遍历(非递归)
题目: 给定一个二叉树,返回它的 后序 遍历. 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [3,2,1] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? 解题思路: 1 ...
- 二叉树——遍历篇(递归/非递归,C++)
二叉树--遍历篇 二叉树很多算法题都与其遍历相关,笔者经过大量学习.思考,整理总结写下二叉树的遍历篇,涵盖递归和非递归实现. 1.二叉树数据结构及访问函数 #include <stdio.h&g ...
随机推荐
- C#winform中DataGridView常用的属性
1.AllowUserToAddRows属性:指示是否向用户显示添加行的选项 AllowUserToOrderColumns属性:指示是否允许通过手动对列重新定位 AllowUserToResizeC ...
- WPF 最大化最小化窗口
public static void FullOrMin(this Window window) { //如果是全屏,则最小化 if (win ...
- anti-pattern - Hard coding
https://en.wikipedia.org/wiki/Hard_coding Considered an anti-pattern, hard coding requires the progr ...
- delphi下TList的用法
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- Linux的权限说明
Linux的权限不是很细致,只有RWX三种r(Read,读取):对文件而言,具有读取文件内容的权限:对目录来说,具有浏览目录的权限.w(Write,写入):对文件而言,具有新增,修改,删除文件内容的权 ...
- 基于java工程开发RMI服务端
ServiceRegist.java import java.rmi.Remote; import java.rmi.RemoteException; public interface Service ...
- go access database demo
package main import ( "database/sql" "fmt" _ "github.com/lib/pq" " ...
- Comparable与Comparator
转载 Comparable与Comparator的区别 (转载) Comparable & Comparator 都是用来实现集合中元素的比较.排序的,只是 Comparable 是在集合内部 ...
- Python中什么是set、更新、遍历set和set的特点
dict的作用是建立一组 key 和一组 value 的映射关系,dict的key是不能重复的. 有的时候,我们只想要 dict 的 key,不关心 key 对应的 value,目的就是保证这个集合的 ...
- Bootstrap 巨幕页头缩略图和警告框组件
一.巨幕组件 //在固定的范围内,有圆角 <div class="container"> <div class="jumbotron"> ...