算法体系结构第十一课

一、先序遍历的序列化与反序列化
1.先序遍历序列化
把一棵树按照某种遍历进行文本格式保存,注意保存时要保存空;

比如一棵树的结构是:
		__1
	   /
	   2__
	   	  \
	   	   3
先序遍历序列化的结果是:1, 2, #, 3, #, #, #,

通过头左右递归的方式往队列里进行添加;

2.先序遍历反序列化
通过给出的用队列表示的序列化结果,把二叉树进行还原

步骤:弹出队列元素,是空返回空,非空就用这个值把结点建立好,再去递归它的孩子们,因为是先序遍历,所以是先左孩子后右孩子

疑问:为何程序敢在没有对队列进行判空的前提下进行队列的弹值
	public static Node preB(Queue<String> preList) {
    
    
		String value = preList.poll();
		if (value == null) {
    
    
			return null;
		}
		......
		...
		}

分析:每次递归时,都会将队列位于头部的元素弹出,而递归函数的数量又恰好是队列的大小,但这又是为什
么呢?

9.9:因为当判断到空的时候,不会递归下去,该递归函数把空返回就结束了,不会进行额外的队列元素的使
用;

二、后序遍历的序列化和反序列化(没有中序,因为它会产生歧义)

1.后序遍历序列化
左右头递归去吧~

2.后序遍历反序列化
左右头的队列进栈,在递归里以头右左的顺序弹出,递归函数以头右左的顺序进行树的建立

三、层序遍历序列化与反序列化

1.层序遍历序列化
准备存放序列化结果的队列和用于层序遍历的队列;
进入层序队列时就序列化,弹出时,它的孩子空就只往ans里加null,非空就加入队列并且序列化;
(大致格式:左右孩子各一个if else)

2.层序遍历反序列化
首先,生成头结点再放入层序队列里迭代,迭代时,先弹出结点,建好左右孩子,再判空是否放入层序队列;

四、多叉树和二叉树的相互转化

1.多叉树转二叉树
把孩子全部放到头结点的左子树的右边界上,不断递归;

先以多叉头结点建立二叉头结点,再以多叉头结点的孩群依次建立二叉头结点的左孩子与左孩子的右边界,但在建立下一个孩子的时候,要提前根据该点对应的多叉结点的孩群建立好该点的左孩子与左孩子的右边界;

coding细节:遍历孩群,左孩子为长兄,左孩子的右边界为次子,长兄建立好后不动,通过cur指针不断建立长兄的右边界,先把长兄的孩群建好后再建立次子们的;

2.二叉树转多叉树
让头结点的长兄去整理这个家庭的次子,完成家庭情况,处理之前长兄要让自己的长子整理自己家庭的家庭情况,处理好之后在去处理次子的,次子们也要让自己的长子整理他自己的家庭情况;

五、求二叉树最宽的层
1.来自基础班的方法
在把元素加入到队列的时候,记录一下队列的大小,在队列的大小之内进行元素的弹出和子元素的加入,以确保把上一层的元素全部弹出后进行下一层宽度的获取;

2.用表的方法
每次把元素加入队列时都要把元素和它所在的层加入表里,弹出元素时,通过表获取它对应的层数,压入子元素时应压入子元素与(父元素压入层数 + 1);
当前结点层数和当前层数相同时,宽度++;
不同时,即遍历到下一层的第一个结点时,进行上一层的总结:
导出上一层的宽度到max,当前层数++,当前宽度 = 1;
注意:最后一层没有下一层对它进行的总结,所以最后一层的宽度只是加载完毕而已,需要在最后进行手动地更新;

3.不用表的方法
弹出结点后对该层的宽度++,将子节点设为下一层的结束,先左后右,
如果当前节点是当前层的末尾节点,导出该层的宽度,宽度归零,下一层的末尾节点盖掉当前层的末尾节点

六、一个具有父节点指针的二叉树,返回某个结点在中序遍历下的后继结点
分两种情况:
1.如果该节点有右子树,那么该节点的后继节点便是右子树的左边界的末尾节点,也就是右子树的左结点的左结点的左结点的…(往右下拐后,往左走到最后)
2.如果该节点n没有右子树,那就不断往上看,直到它上面的某个结点x是x的父节点的左孩子,那么该父节点便是结点n的后继结点(往左上走,直到能右拐)

如果一直往上走到头都没能右拐(node没能成为parent的左孩子),说明它就是中序遍历的最后一个结点,没有后继;




当前未解决的代码:
用一个栈实现二叉树的后序遍历、
命令行直观显示二叉树
一个二叉树结论的证明

Guess you like

Origin blog.csdn.net/dgytjhe/article/details/120184381