二叉树的先序、中序以及后序遍历(递归 && 非递归)
树节点定义:
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 ...
随机推荐
- 图片lightbox2
1. 官网下载 http://lokeshdhakar.com/projects/lightbox2/ 2.引入 css jquery js 3. HTML格式 <a href=" ...
- activitydialog
给Activity设置Dialog属性,点击区域外消失:,activitydialog 1.在AndroidManifest.xml中给Activity设置样式: <activity ...
- 常用ARM汇编指令
常用ARM汇编指令 [日期:2012-07-14] 来源:Linux社区 作者:xuyuanfan77 [字体:大 中 小] 在嵌入式开发中,汇编程序常常用于非常关键的地方,比如系统启动时初 ...
- C语言文法定义及C程序的推导过程
program à external_declaration | program external_declaration <程序> -> <外部声明> | < ...
- Android源码剖析之Framwork层后记篇(硬件消息传递、apk管理、输入法框架、编译过程)
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 既然写到后记篇,就代表本系列到此为止,暂时告一段落:其他一些Manager随后有时间再补,就像源码的 ...
- CSS之position
1.当元素使用了position:relative或者position:absolute才能激活 top left 等属性的使用! 2.使用了position后,display无论设置了什么值都会 ...
- 如何使用批处理解决批量telnet命令的输入
用telnet命令做不了自动,因为如果成功telnet了,telnet就控制输入了.其实,不用那么麻烦,您下载一个微软官方的扫描器叫portqry,用一句for读取您文件里的ip和port,执行就行了 ...
- TCP keepalive overview
2. TCP keepalive overview In order to understand what TCP keepalive (which we will just call keepali ...
- 有了JSON.stringify(),处理json将变得更简单!!
之前处理json 需要拼接json字符串,但是,如果用上JSON.stringify()的话,忘了json语法以没关系了..... @{ ViewBag.Title = "GetStr&qu ...
- Unofficial Windows Binaries for Python Extension Packages
http://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy