序列化二叉树
三大遍历+层序遍历序列化
结构
public static class Node{
int value;
Node left;
Node right;
public Node(int value){
this.value=value;
}
}
四大遍历序列化
public static void preSerializable(Node root,Queue<Integer> queue){
if(root==null) queue.add(null);
else{
queue.add(root.value);
preSerializable(root.left,queue);
preSerializable(root.right,queue);
}
}
public static void inSerializable(Node root,Queue<Integer> queue){
if(root==null) queue.add(null);
else{
inSerializable(root.left,queue);
queue.add(root.value);
inSerializable(root.right,queue);
}
}
public static void posSerializable(Node root,Queue<Integer> queue){
if(root==null) queue.add(null);
else{
posSerializable(root.left,queue);
posSerializable(root.right,queue);
queue.add(root.value);
}
}
层序遍历
public static void levelSerial(Node head){
Queue<String> data=new LinkedList<>();
if(head==null) {
data.add(null);
return;
} else {
//遍历依赖的队列
Queue<Node> queue = new LinkedList<>();
queue.add(head);
data.offer(String.valueOf(head.value));
while (!queue.isEmpty()) {
head = queue.poll();
if (head.left != null) {
queue.offer(head.left);
data.offer(String.valueOf(head.left));
} else {
data.offer(null);
}
if (head.right != null) {
queue.offer(head.right);
data.offer(String.valueOf(head.right));
} else {
data.offer(null);
}
}
}
}
反序列二叉树(构建)
关键:先的抓到本结点,然后去构建子树和右树
先序遍历序列化后的构建
public static Node unPreSerial(Queue<String> queue){
String value = queue.poll();
if(value==null) return null;
Node head=new Node(Integer.valueOf(value));
head.left= unPreSerial(queue);
head.right=unPreSerial(queue);
return head;
}
后序遍历序列化后的构建
后序遍历时候,中间结点是最后面的,当时我们需要最先抓到中间结点
方法:左右中===>中右左
public static void unPosSerial(Queue<String> queue){
String value = queue.poll();
if(value==null) return;
Stack<String> stack=new Stack<>();
stack.push(value);
while(!queue.isEmpty()){
stack.push(queue.poll());//左右中---中右左
}
}
拿到中右左的序列就好先构建中间结点了
public static Node unPosSerial(Stack<String> stack){
String value=stack.pop();
if(value==null) return null;
else{
Node head=new Node(Integer.valueOf(value));
head.left=unPosSerial(stack);
head.right=unPosSerial(stack);
return head;
}
}
层序遍历序列化的构建
public static Node GenerateNode(String value){
if(value==null) return null;
else{
return new Node(Integer.valueOf(value));
}
}
public static Node unLevel(Queue<String> data){
String value = data.poll();
if(value==null){
return null;
}else{
Queue<Node> queue=new LinkedList<>();
Node head = Generate(value);
queue.add(head);
while(!queue.isEmpty()){
Node cur = queue.poll();//如果一层弹完了,data里的对应层的下一层的结点也是会弹完的(queue弹一层,data要弹出它的孩子)
cur.left=Generate(data.poll());
cur.right=Generate(data.poll());
if(cur.left!=null) queue.add(cur.left);
if(cur.right!=null) queue.add(cur.right);
}
return head;
}
}
再次强调:构建二叉树,首先要抓到本节点的node(先new中间的结点,再后面去构建它的左右子树)
强加练习:给出中序和后序/前序遍历的数组,构建二叉树
中序加后序:
思想:后序数组最后一个元素确定了中间结点的值root,在中序数组中找到该值,以此分割中序左数组和右边数组,左数组对应左子树,右数组对应右子树,
划分后序数组的左右子数组:
根据中序的左子数组的长度是等于后序数组的左子数组的长度,划分好后序左子数组后,后面的元素,除了最后一个元素,都是后序的右子数组
中序左子数组和后序左子数组=====>去构建左子树(root.left)
右子数组一样
发现:这个过程是一个递归过程
代码
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
//构造结点,构造左子树,构造右子树
return process(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
}
public TreeNode process(int[] inorder,int inleft,int inright,int[] postorder,int posleft,int posright){
if(inright<inleft) return null;
if(inright==inleft) return new TreeNode(inorder[inleft]);
//正常情况
//1:得到根结点:对于数组元素的取值,需要用左右遍历
TreeNode root=new TreeNode(postorder[posright]);
int rootIndex=0;
for(int i=inleft;i<=inright;i++){
if(inorder[i]==root.val){
rootIndex=i;//找到根节点在中序数组中的位置
break;
}
}
//构建左子树(前闭后开),左参数是index,右参数是长度
root.left=process(inorder,inleft,rootIndex-1,postorder,posleft,posleft+(rootIndex-inleft-1));
root.right=process(inorder,rootIndex+1,inright,postorder,posleft+(rootIndex-inleft),posright-1);
return root;
}
}
中序和前序
思想:和前面一样
代码
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return process(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
public TreeNode process(int[] preorder,int preLeft,int preRight,int[] inorder,int inLeft,int inRight){
//basecase
if(inLeft>inRight) return null;
if(inLeft==inRight) return new TreeNode(inorder[inLeft]);
//正常情况
TreeNode root=new TreeNode(preorder[preLeft]);
int rootIndex=0;
for(int i=inLeft;i<=inRight;i++){
if(root.val==inorder[i]){
rootIndex=i;
break;
}
}
//构建子树
root.left=process(preorder,preLeft+1,preLeft+(rootIndex-inLeft),inorder,inLeft,rootIndex-1);
root.right=process(preorder,preLeft+(rootIndex-inLeft)+1,preRight,inorder,rootIndex+1,inRight);
return root;
}
}
有序数组构建BST(二查搜索树)
递归思想:
每次取中间的元素作为root,分割数组左右子数组,分别作为左右子树
代码
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return build(nums,0,nums.length-1);
}
public TreeNode build(int[] nums ,int L,int R){
//每次取中间,取到的作为root,左子树用左数组,右子树用右数组
if(L>R) return null;
int mid=L+((R-L)>>1);
TreeNode root=new TreeNode(nums[mid]);
root.left=build(nums,L,mid-1);
root.right=build(nums,mid+1,R);
return root;
}
}
总结:
1:每次都是先抓到本结点,才可以处理它的左右子树
2:如果是递归思想:每次处理好了本结点,处理它的左右孩子的时候,直接递归