树---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一直跟踪记录广度优先进入队列的节点即可。(3nlast=最新加入队列的最右节点。

 

过程:起始时last=1: pop1换行,push2 3),nlast=2,3,最后等于3(这一行最右边的节点3)就是nlast的位置,队列(2,3),此时让last=nlast=3 继续新一行打印。

pop 2push 4nlast=4;再继续 pop 3, push 5 6, nlast=5 6 ,这时搜索到last了,表示要换行,而nlast=6last=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();}


0 0
原创粉丝点击