树---2.遍历
来源:互联网 发布:创维网络电视价格 编辑:程序博客网 时间:2024/06/03 08:47
1.先中后层次遍历时间复杂度均为O(n)
先序遍历(根-->左子树-->右子树)12-9-76-35-22-16-48-46-40-90-
中序遍历(左子树-->跟-->右子树)9--12--16--22--35--40--46--48--76--90--
后序遍历(左子树-->右子树-->根)9---16---22---40---46---48---35---90---76---12---
2.二叉树结构和插入
public class BTree {int data;BTree left;BTree right;public BTree(int data){this.data=data;left=null;right=null;}public void insert(BTree root,int data){//插入if(data>root.data){//向右走if(root.right==null){root.right=new BTree(data);}else{this.insert(root.right, data);}}else{//向左走if(root.left==null){root.left=new BTree(data);}else{this.insert(root.left, data);}}}
2.1先序遍历(递归和非递归)
非递归:先向左走到尽头 访问节点--入栈,当节点P为空时开始pop p=p.right
public void preOrderTraverse(BTree root){//递归先序遍历,root->left->rightif(root!=null){System.out.print(root.data+"-->");preOrderTraverse(root.left);preOrderTraverse(root.right);}}
public void preOrderTraverse2(BTree root){//非递归先序遍历.访问->入栈->往左走,为空时开始pop,p=p.rightif(root==null) return;BTree p=root;Stack<BTree> s=new Stack();ArrayList<BTree> list=new ArrayList();//记录先序遍历的各节点顺序while(p!=null||!s.isEmpty()){//将左孩子入栈if(p!=null){//向左走到尽头,每个节点入栈之前先访问list.add(p);//list用来记录所有节点的顺序,若直接输出值可以不用System.out.print(p.data+"-->");s.push(p);p=p.left;}else{//p为空代表,左子树访问完,该pop新节点并切换它的右孩子p=s.pop();p=p.right;}}Iterator<BTree> it=list.iterator();System.out.println();System.out.println("list:");while(it.hasNext()){System.out.print(it.next().data+"-->");}}
2.2中序遍历(递归和非递归)
非递归:左子树--根--右子树,先往左所有节点入栈,当p为空时开始pop--访问--p=p.right
public void inOrderTraverse(BTree root){//递归中序遍历,left->root->rightif(root!=null){inOrderTraverse(root.left);System.out.print(root.data+"-->");inOrderTraverse(root.right);}}public void inOrderTraverse2(BTree root){//非递归中序遍历,先左孩子入栈,p为空时:pop节点 访问, 节点,=右孩子if(root==null) return;BTree p=root;Stack<BTree> s=new Stack();while(p!=null||!s.isEmpty()){if(p!=null){//将所有孩子入栈(先入栈后访问),向左走走到底s.push(p);p=p.left;}else{//当p为空时,pop--访问--p=p.right,访问一定要在p=p.right之前p=s.pop();System.out.print(p.data+"-->");p=p.right;}}}
2.3后序遍历(递归和非递归)
非递归:左子树--右子树--根,可以理解成为:根--右子树--左子树 的倒序,自己举例子就会发现,所以借助中间栈来保存根--右--左的结果,最后在pop就是后序遍历的结果了
即:后序遍历可以理解成另一种先序遍历。
public void postOrderTraverse(BTree root){//递归后序遍历,left,right,rootif(root!=null){postOrderTraverse(root.left);postOrderTraverse(root.right);System.out.print(root.data+"-->");}}public void postOrderTraverse2(BTree root){//非递归后续遍历if(root==null) return;BTree p=root;Stack<BTree> s=new Stack();Stack<BTree> output=new Stack();//构造一个中间栈来存储逆后续遍历的结果while(p!=null||!s.isEmpty()){//后序遍历可以是左子树->右子树->根遍历方式//可以将其理解为根---右---左的倒序,或者说可以理解成另外一种先序遍历if(p!=null){//往右走,入栈 output.push(p);s.push(p);p=p.right;}else{p=s.pop();p=p.left;}}while(!output.isEmpty()){//将中间栈pop出就是后序遍历的实际结果System.out.print(output.pop().data+"-->");}}
2.4层次遍历
借助队列,访问节点,左孩子入队,右孩子入队,出队列
public void levelOrderTraverse(BTree root){//借助队列,访问节点,左孩子入队,右孩子入队if(root==null) return;Queue<BTree> queue=new LinkedList();queue.add(root);while(!queue.isEmpty()){BTree p=queue.poll();//获取并移除对头,如果队列为空则返回nullSystem.out.print(p.data+"-->");if(p.left!=null){queue.add(p.left);}if(p.right!=null){queue.add(p.right);}}}
按照行号打印层次二叉树遍历结果
按照图的层次搜索(队列),并且将行号等相关信息打印出来。关键点在于如何换行:
设定两个变量:
last:正在打印的当前行的最右节点
nLast:下一行的最右节点。
(1)从左->右,发现last节点,则表示该换行。(2)此时last=nlast。而nlast一直跟踪记录广度优先进入队列的节点即可。(3)nlast=最新加入队列的最右节点。
过程:起始时last=1: pop出1换行,push(2 3),nlast=2,3,最后等于3(这一行最右边的节点3)就是nlast的位置,队列(2,3),此时让last=nlast=3 继续新一行打印。
pop 2,push 4,nlast=4;再继续 pop 3, push 5 6, nlast=5 6 ,这时搜索到last了,表示要换行,而nlast=6,last=nlast=6,继续新一行打印。队列(4 5 6)
public void myPrint(BTree root){if(root==null) return;BTree last=root;BTree nlast=root;Queue<BTree> queue=new LinkedList();queue.add(root);while(!queue.isEmpty()){BTree p=queue.poll();//获取对头,队列为空则返回nullSystem.out.print(p.data+"\t");if(p.left!=null){nlast=p.left;queue.add(p.left);}if(p.right!=null){nlast=p.right;queue.add(p.right);}if(p==last){System.out.println();last=nlast;}}}
按行打印:1297635902248164640
(2)
二叉树的序列化与反序列化
用文件记录二叉树,再凭借文件还原二叉树。根据先序中序后序 按层遍历实现序列化。
给定一个二叉树头结点root,并已知二叉树节点值类型为32位整型,设计一种二叉树序列化和反序列化的方法,并用代码实现。
(1)先序遍历二叉树进行序列化(中序、后序)栈
1)遇到节点为null时用#!表示
2)用!表示一个值的结束,避免歧义(比如12到底是1,2两个节点,还是一个节点,。而1!2!,就明确表示2个节点,12!表示一个节点)
3)!区分还有一个好处就是,调用String的split ( “!”)将系列化结果转成数组
实现过程:
1)将树按照先序遍历结果转成字符串str
2)Str写入文件中,反序列化得到文件中字符串str2(例子中不写该过程)
3)Str.split( “!”),String-->value [ ],每个元素代表节点
4)按照先序遍历开始插入
public void treeSerialize(BTree root){if(root==null) return;String str1=null;//序列化结果,初始时为nullString str2=null;str1=preOrderStr(root);//字符串表示线序遍历二叉树,遇到空节点引入#,这里不实现了省略try{FileOutputStream fos=new FileOutputStream(new File("tree.txt"));BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(fos));bw.write(str1);//将树的字符串写入文件中FileInputStream fis=new FileInputStream(new File("tree.txt"));BufferedReader br=new BufferedReader(new InputStreamReader(fis));str2=br.readLine();bw.close();br.close();fos.close();fis.close();}catch(IOException e){e.printStackTrace();}String[] values=str2.split("!");//values先序插入树}
(2)按层遍历(用队列实现)
public String levelTra(BTree root){StringBuffer sb=new StringBuffer();Queue<BTree> que=new linkedList();//BTree temp=null;que.add(root);while(!que.isEmpty()){BTree p=que.poll();if(p==null){sb.append("#!")}sb.append(p.val+"!");if(p.left!=null){que.add(p.left);}else{que.add(null)}if(p.right!=null){que.add(p.right);}else{que.add(null);}}return sb.toString();}
- 树---2.遍历
- 树-遍历
- 遍历树
- 二叉树遍历、分层遍历
- 二叉树遍历,深度有限遍历,广度优先遍历,前序中序后续优先遍历,层次遍历
- 树遍历方式总结:层次遍历、先序遍历、中序遍历、后序遍历
- 遍历节点树、遍历元素树、遍历API、查找 API
- 二叉树的遍历(层遍历和深度遍历)
- java遍历树(深度遍历和广度遍历)
- 二叉树的前序中序后序遍历,非递归遍历 层次遍历
- 树 前序遍历,中序遍历,后序遍历
- 二叉树的先中后序遍历,递归遍历,非递归遍历
- 二叉树,前中后遍历,层遍历
- 二叉树层次遍历和深度遍历
- 树遍历之推广到图遍历
- 二叉树遍历 层序遍历
- 二叉树遍历-----前序后序迭代遍历的新思路
- 二叉树层次遍历和深度遍历
- 1013
- [LeetCode] 71. Simplify Path java
- (转)View.inflate和LayoutInflater的inflate方法区别
- maven国内镜像(maven下载慢的解决方法)
- 局部变量返回值问题
- 树---2.遍历
- MFC使用HttpGet和HttpPost方法与服务器通信
- [LeetCode] 58. Length of Last Word java
- 队列
- librtmp 日志的修改和操作
- 设计模式之工厂方法模式|抽象工厂模式
- Web前端代码构建优化
- JAVA中String字符串的各种基本操作
- Debugging Tips and Tricks for C++ in Visual Studio