【数据结构】二叉树的前中后序遍历递归和非递归实现
2016-01-28 22:24
597 查看
二叉树有很多操作,而二叉树的遍历只是其中的一个基本操作。
二叉树的遍历方式有3种:前序遍历,中序遍历,后序遍历。前中后遍历顺序是根据什么时候访问根节点来说的。
1.前序遍历
前序遍历也叫先序遍历。思路是先访问根节点,然后遍历左子树,最后遍历右子树。直到所有的节点都遍历完。
2.中序遍历
中序遍历的遍历步骤是先遍历左子树,然后访问根节点,最后遍历右子树。直到所有的节点都遍历完。
3.后序遍历
后序遍历的遍历顺序是先遍历左子树,然后遍历右子树,最后访问根节点。直到所有的节点都遍历完。
如果你仔细观察以上的文字,你会觉得所描述的遍历是非常抽象的,根节点,哪里的根节点?左子树,哪个根节点的左子树?右子树,哪个根节点的右子树?如果你再熟悉递归,你会立马想到递归,因为递归可以把抽象的问题一步一步来解决。用递归来遍历二叉树很简单,代码一目了然。
假如有这样一棵二叉树:
对于这样一棵树,前序遍历顺序是:RACDB
中序遍历的顺序是:CADRB
后序遍历的顺序是:CDABR
二叉树的遍历用递归来描述是简洁了,但是有时候考虑到效率。我们会用栈来模拟递归的过程。由于递归过程有栈帧,所以保存好栈帧是非递归遍历二叉树的难点。
下面是遍历二叉树的代码实现:
二叉树的遍历方式有3种:前序遍历,中序遍历,后序遍历。前中后遍历顺序是根据什么时候访问根节点来说的。
1.前序遍历
前序遍历也叫先序遍历。思路是先访问根节点,然后遍历左子树,最后遍历右子树。直到所有的节点都遍历完。
2.中序遍历
中序遍历的遍历步骤是先遍历左子树,然后访问根节点,最后遍历右子树。直到所有的节点都遍历完。
3.后序遍历
后序遍历的遍历顺序是先遍历左子树,然后遍历右子树,最后访问根节点。直到所有的节点都遍历完。
如果你仔细观察以上的文字,你会觉得所描述的遍历是非常抽象的,根节点,哪里的根节点?左子树,哪个根节点的左子树?右子树,哪个根节点的右子树?如果你再熟悉递归,你会立马想到递归,因为递归可以把抽象的问题一步一步来解决。用递归来遍历二叉树很简单,代码一目了然。
假如有这样一棵二叉树:
对于这样一棵树,前序遍历顺序是:RACDB
中序遍历的顺序是:CADRB
后序遍历的顺序是:CDABR
二叉树的遍历用递归来描述是简洁了,但是有时候考虑到效率。我们会用栈来模拟递归的过程。由于递归过程有栈帧,所以保存好栈帧是非递归遍历二叉树的难点。
下面是遍历二叉树的代码实现:
package 二叉树的遍历; import java.util.*; import java.io.*; class BitNode { //声明一颗树的节点 char data; BitNode LChild; BitNode RChild; } public class Main { static BitNode[] bits=new BitNode[4]; /* *树的结构 * R * / \ * A B * / \ * C D * */ public static void createTree(BitNode root) { for (int i=0;i < 4;i++) { bits[i] = new BitNode(); bits[i].data = (char)('A' + i); } root.data = 'R'; root.LChild = bits[0]; root.RChild = bits[1]; bits[0].LChild = bits[2]; bits[0].RChild = bits[3]; } /* * 后续遍历: *从根节点出发,只要当前节点存在,或者栈不为空,重复下面的操作: *(1)从当前节点开始,进栈并走左子树,直到左子树为空 *(2)如果栈顶节点的右子树为空,或者栈顶结点的右孩子为刚才访问过的节点, * 则退栈并访问,然后将当前节点指针置为空。 *(3)否则走右子树。 */ public static void post2(BitNode root) { Stack<BitNode> stack=new Stack<BitNode>(); BitNode p,q=null; p=root; while(p!=null||!stack.empty()) { while(p!=null) { stack.push(p); p=p.LChild; } if(!stack.empty()) { p=stack.peek(); if(p.RChild==q||p.RChild==null) /*无右孩子,或着右孩子以遍历过*/ { visit(stack.pop());//访问根节点 q=p;//保存到q,为下一次已处理节点做前驱 p=null; } else{ p=p.RChild; } } } } public static void post1(BitNode root) { if (root == null) return; post1(root.LChild); post1(root.RChild); visit(root); } /* * 中序遍历: *从根节点出发,只要当前节点存在,或者栈不为空,重复下面的操作: *(1)如果当前节点存在,则进栈并走左子树。 *(2)否则退栈并访问,然后走右子树 */ public static void inorder2(BitNode root) { Stack<BitNode> stack=new Stack<BitNode>(); BitNode p; p=root; while(p!=null||!stack.empty()) { if(p!=null) { stack.push(p); p=p.LChild; } else { p=stack.pop(); visit(p); p=p.RChild; } } } public static void inorder1(BitNode root) { if (root == null) return; inorder1(root.LChild); visit(root); inorder1(root.RChild); } public static void pre1(BitNode root) { if (root == null) return; visit(root); pre1(root.LChild); pre1(root.RChild); } public static void pre2(BitNode root) { Stack<BitNode> stack=new Stack<BitNode>(); stack.push(root); while (!stack.empty()) { BitNode node=stack.pop(); visit(node); if (node.RChild != null) { stack.push(node.RChild); } if (node.LChild != null) { stack.push(node.LChild); } } } public static void visit(BitNode bit) { System.out.print(bit.data); } public static void main(String[] args) { BitNode root=new BitNode(); createTree(root); System.out.println("先序递归遍历"); pre1(root); System.out.println("\n\n先序非递归遍历"); pre2(root); System.out.println("\n\n中序递归遍历"); inorder1(root); System.out.println("\n\n中序非递归遍历"); inorder2(root); System.out.println("\n\n后序递归遍历"); post1(root); System.out.println("\n\n后序非递归遍历"); post2(root); } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树