二叉树的递归和非递归前、中、后序遍历
2017-05-06 11:27
281 查看
1、二叉树树的递归遍历,程序简洁,前、中、后遍历相差不大。
本例中用到的二叉树为:
前序遍历为:10 6 4 8 14 12 16
中序遍历为:4 6 8 10 12 14 16
后续遍历为:4 8 6 12 16 14 10
非递归代码:`
递归版的前序遍历:
递归版的中序遍历:
递归版的后序遍历
从上面的代码块可以看出,递归版的前、中、后序遍历唯一的差别处就是什么时候将根节点保存到list中;
2、非递归版的二叉树遍历
很多的递归问题都可以用循环来解决,事实上递归也是基于栈来实现的,但是利用栈实现递归的时候,就得考虑栈的劣势可能引发的问题。
这儿顺便总结一下递归用栈的缺点:
递归由于是函数调用自身,而函数调用是有时间和空间消耗的:每一次函数调用都需要在内存栈中分配空间以保存参数、临时变量及返回地址,而且往栈里亚人和弹出数据都需要时间。
递归中有很多计算都是重复的,从而对性能能带来很大的负面影响。这一点在斐波那契数列的计算上体现尤其的明显。
除了效率之外,递归还有可能引起更严重的问题:调用栈溢出。每一调用函数都需要在内存栈中为其分配空间,而每个进程的栈容量是有限的,当递归调用的层级太多时,就会超出栈的容量,从而导致调用栈溢出。
虽然栈的递归使用有很多的问题,但是在非递归计算过程中,栈的使用又是不可避免的,特别是在树的循环遍历中需要保存之前访问过的节点,那么这时也只能使用栈来中转啦!
非递归前序遍历代码:
非递归中序遍历代码:
非递归后续遍历代码:
后续遍历代码较前、中序遍历代码有较大的改动因为根节点是最后被访问的。但是通过观察后续遍历的结果:4 8 6 12 16 14 10 ,其逆过来看为:10 14 16 12 6 8 4,再看前序遍历的结果:10 6 4 8 14 12 16,二者比较发现,逆后序遍历就是在前序遍历的基础上稍作改动:先访问根节点,再访问右孩子,再访问做孩子,结果就是逆后序遍历,得到逆后序遍历,再将其反转,就可以得到后续遍历的结果。
测试用的代码如下:
前、中、后序遍历结果如下:
本例中用到的二叉树为:
前序遍历为:10 6 4 8 14 12 16
中序遍历为:4 6 8 10 12 14 16
后续遍历为:4 8 6 12 16 14 10
非递归代码:`
递归版的前序遍历:
private static void TraverseTree(BinaryTreeNode root,ArrayList<Integer> list) { if(root==null) return ; list.add(root.val); if(root.leftchild!=null) TraverseTree(root.leftchild,list); if(root.rightchild!=null) TraverseTree(root.rightchild,list); }
递归版的中序遍历:
private static void TraverseTree(BinaryTreeNode root,ArrayList<Integer> list) { if(root==null) return ; if(root.leftchild!=null) TraverseTree(root.leftchild,list); list.add(root.val); if(root.rightchild!=null) TraverseTree(root.rightchild,list); }
递归版的后序遍历
private static void TraverseTree(BinaryTreeNode root,ArrayList<Integer> list) { if(root==null) return ; if(root.leftchild!=null) TraverseTree(root.leftchild,list); if(root.rightchild!=null) TraverseTree(root.rightchild,list); list.add(root.val); }
从上面的代码块可以看出,递归版的前、中、后序遍历唯一的差别处就是什么时候将根节点保存到list中;
2、非递归版的二叉树遍历
很多的递归问题都可以用循环来解决,事实上递归也是基于栈来实现的,但是利用栈实现递归的时候,就得考虑栈的劣势可能引发的问题。
这儿顺便总结一下递归用栈的缺点:
递归由于是函数调用自身,而函数调用是有时间和空间消耗的:每一次函数调用都需要在内存栈中分配空间以保存参数、临时变量及返回地址,而且往栈里亚人和弹出数据都需要时间。
递归中有很多计算都是重复的,从而对性能能带来很大的负面影响。这一点在斐波那契数列的计算上体现尤其的明显。
除了效率之外,递归还有可能引起更严重的问题:调用栈溢出。每一调用函数都需要在内存栈中为其分配空间,而每个进程的栈容量是有限的,当递归调用的层级太多时,就会超出栈的容量,从而导致调用栈溢出。
虽然栈的递归使用有很多的问题,但是在非递归计算过程中,栈的使用又是不可避免的,特别是在树的循环遍历中需要保存之前访问过的节点,那么这时也只能使用栈来中转啦!
非递归前序遍历代码:
public static void preOrderTraversal(BinaryTreeNode root,ArrayList<Integer> list){ if(root==null) return ; Stack<BinaryTreeNode> s=new Stack<BinaryTreeNode>(); BinaryTreeNode p=root; while(p!=null||!s.isEmpty()){ while(p!=null){ list.add(p.val); s.push(p); p=p.leftchild; } if(!s.isEmpty()){ p=s.pop(); p=p.rightchild; } } }
非递归中序遍历代码:
public static void InOrderTraversal(BinaryTreeNode root ,ArrayList<Integer> list){ Stack<BinaryTreeNode> stack=new Stack<BinaryTreeNode>(); if(root==null) return ; BinaryTreeNode p=root; while(p!=null||!stack.isEmpty()){ while(p!=null){ stack.push(p); p=p.leftchild; } if(!stack.isEmpty()){ p=stack.pop(); list.add(p.val); p=p.rightchild; } } }
非递归后续遍历代码:
public static void PostOrderTraversal(BinaryTreeNode root,ArrayList<Integer> list){ if(root==null) return ; Stack<BinaryTreeNode> stack=new Stack<BinaryTreeNode>(); Stack<Integer> s=new Stack<Integer>(); BinaryTreeNode p=root; while(p!=null||!stack.isEmpty()){ while(p!=null){ stack.push(p); s.push(p.val); p=p.rightchild; } if(!stack.isEmpty()){ p=stack.pop(); p=p.leftchild; } } while(!s.isEmpty()){ list.add(s.pop()); } }
后续遍历代码较前、中序遍历代码有较大的改动因为根节点是最后被访问的。但是通过观察后续遍历的结果:4 8 6 12 16 14 10 ,其逆过来看为:10 14 16 12 6 8 4,再看前序遍历的结果:10 6 4 8 14 12 16,二者比较发现,逆后序遍历就是在前序遍历的基础上稍作改动:先访问根节点,再访问右孩子,再访问做孩子,结果就是逆后序遍历,得到逆后序遍历,再将其反转,就可以得到后续遍历的结果。
测试用的代码如下:
class BinaryTreeNode{ int val; BinaryTreeNode leftchild=null; BinaryTreeNode rightchild=null; public BinaryTreeNode(int val){ this.val=val; } } public class TreeTraverse { public static void main(String[] args) { BinaryTreeNode root=new BinaryTreeNode(10); BinaryTreeNode node6=new BinaryTreeNode(6); BinaryTreeNode node14=new BinaryTreeNode(14); root.leftchild=node6; root.rightchild=node14; BinaryTreeNode node4=new BinaryTreeNode(4); BinaryTreeNode node8=new BinaryTreeNode(8); node6.leftchild=node4; node6.rightchild=node8; BinaryTreeNode node12=new BinaryTreeNode(12); BinaryTreeNode node16=new BinaryTreeNode(16); node14.leftchild=node12; node14.rightchild=node16; ArrayList<Integer> list= new ArrayList<Integer>(); TraverseTree(root,list); preOrderTraversal(root,list); InOrderTraversal(root,list); PostOrderTraversal(root,list); System.out.println(list); } }
前、中、后序遍历结果如下:
前序遍历结果为: [10, 6, 4, 8, 14, 12, 16] 中序遍历结果为: [4, 6, 8, 10, 12, 14, 16] 后序遍历结果为: [4, 8, 6, 12, 16, 14, 10]
相关文章推荐
- 用非递归实现二叉树的前序、中序、后序、层次遍历,用递归实现查找、统计个数、比较、求深度
- 数据结构:二叉树的前序,中序,后序遍历(递归和非递归)
- 二叉树的先序,中序,后序,层次的递归及非递归遍历
- java语言实现二叉树的前序、中序与后序遍历(递归与非递归) 层次遍历
- 二叉树的前、中、后序遍历(递归与非递归)
- 二叉树的前、中、后序遍历(递归和非递归)、层序遍历、深度、叶子节点个数
- 数据结构---二叉树的前序、中序、后序遍历的递归和非递归 实现(C++)
- c++实现二叉树的非递归创建以及非递归先序、中序、后序遍历
- C++二叉树之构造拷贝赋值,递归和非递归的前序遍历,中序遍历和后序遍历,以及层序遍历
- 二叉树详解及二叉树的前序、中序、后序遍历(递归和非递归)
- 二叉树的建树、遍历(先序、中序、后序、层次)(递归和非递归)--Java实现
- 二叉树前、中、后序遍历(递归与非递归)
- JAVA实现二叉树的前、中、后序遍历(递归与非递归)
- 二叉树的深度优先dfs遍历(前序、中序和后序;递归与非递归)
- 多叉树(二叉树)的递归与非递归的后序遍历
- 构建二叉树(据后序遍历序列)---后续遍历二叉树(递归与非递归)
- java语言实现二叉树的前序、中序与后序遍历(递归与非递归)
- 二叉树的先序中序后序遍历 (递归和非递归)
- 二叉树2:层次遍历方式及先序、中序、后序(递归与非递归)遍历方式
- 二叉树的前序、中序、后序遍历(递归与非递归)