二叉树总结(序列化与反序列化)
序列化(以先序为例,中序后序同理)
/**
* 序列化二叉树(先序为例)
* 1、假设序列结果为字符串str,初始化str为"";
* 2、先序遍历二叉树,如果遇到空节点,在str后面加上“#!”
* “#”不是节点为空,“!”表示一个节点值的结束。不加结
* 束符号,可能根据序列化字符串产生多颗树,存在歧义。
* 3、如果遇到非空节点,假设节点值为“3”,就在str末尾加
* 上“3!”
*
* @param node 二叉树的头结点
* @return 序列化的字符串
*/
public String serializeBinaryTree(CreateBinaryTree.TreeNode node) {
if (node == null) {
System.out.print("#!");
return "#!";
}
System.out.print(node.val + "!");
String sLeft = serializeBinaryTree(node.left);
String sRight = serializeBinaryTree(node.right);
return node.val + "!" + sLeft + sRight;
}
反序列化(以先序为例,中序后序同理)
/**
* 反序列化二叉树(先序为例)
*
* @param str 序列化的字符串
*/
public CreateBinaryTree.TreeNode deserializeBinaryTree(String str) {
//特殊输入
if (str == null || str.length() <= 0) return null;
String[] nodes = str.split("!");
//调用反序列化函数
CreateBinaryTree.TreeNode headNode = deserializeBinaryTreeCode(nodes);
return headNode;
}
int index = 0;//数组下标索引
/**
* 反序列化代码(递归实现)
* @param nodes 序列化之后的数组
* @return 二叉树头结点
*/
private CreateBinaryTree.TreeNode deserializeBinaryTreeCode(String[] nodes) {
if (nodes[index].equals("#")){
//下标向后走
index++;
//返回空节点
return null;
}else {
//如果不为空结点,则先恢复这个结点
CreateBinaryTree.TreeNode node = new CreateBinaryTree().new TreeNode(0);
//恢复节点值
node.val = Integer.valueOf(nodes[index]);
//千万注意在递归调用之前(使用了一个元素建立结点之后),要将index向后移动1位
index++;
//恢复左子树
node.left = deserializeBinaryTreeCode(nodes);
//恢复右子树
node.right = deserializeBinaryTreeCode(nodes);
//建立二叉树完成,返回根结点
return node;
}
}
附:创建二叉树的完整代码
package BinaryTree;
import java.util.ArrayList;
/**
* 创建二叉树
* Created by Wyd on 2018/3/24.
*/
public class CreateBinaryTree {
/**
* 二叉树节点结构
*/
class TreeNode{
int val; //节点值
TreeNode left; //左孩子
TreeNode right;//右孩子
public TreeNode(int val) {
this.val = val;
}
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 根据分层遍历生成二叉树
* @param array 分层遍历的序列数组
* @return 生成树的头结点
*/
public TreeNode createBinaryTreeByLayerErgodic(int[] array){
ArrayList<TreeNode> treeNodes = new ArrayList<>(); //用于存放树的节点
//根据数组生成树的初始节点
for (int i = 0; i < array.length; i++) {
TreeNode treeNode = new TreeNode(array[i], null, null);
treeNodes.add(treeNode);//生成的节点存放到ArrayList中
}
//判断传过来的数组是否为空数组
if (treeNodes.size()>0){
//这里只判断到倒数第二个非叶子节点
for (int i = 0; i < (array.length/2-1); i++) {
//判断左节点是否为空
if (treeNodes.get(2*i+1)!=null){
treeNodes.get(i).left = treeNodes.get(2*i+1);
}
//判断右节点是否为空
if (treeNodes.get(2*i+2)!=null){
treeNodes.get(i).right = treeNodes.get(2*i+2);
}
}
}else {
return null;
}
//处理最后一个非叶子节点
int lastRootNode = treeNodes.size() / 2 - 1;//获得最后一个非叶子节点
//左孩子
treeNodes.get(lastRootNode).left = treeNodes.get(2*lastRootNode+1);
//判断是否存在右孩子
if (treeNodes.size()%2==1){
treeNodes.get(lastRootNode).right = treeNodes.get(2*lastRootNode+2);
}
return treeNodes.get(0);
}
/**
* 根据先序和中序遍历序列生成二叉树
* 只要先序,中序,后序中的两个序列
* 就能生成一个二叉树,这里以先序和
* 中序为例
* @param pre 先序序列数组
* @param preStart 先序序列的开始下标
* @param preEnd 先序序列的结束下标
* @param mid 中序序列数组
* @param midStart 中序序列的开始下标
* @param midEnd 中序序列的结束下标
* @return 生成树的头结点
*/
public TreeNode creatBinaryTreeByPreMid(int[] pre,int preStart,int preEnd,int mid[],int midStart,int midEnd){
//判断结束标记
if (preStart>preEnd||midStart>midEnd){
return null;
}
//根据先序遍历得到根节点(因为下面使用的是递归,所以这个根节点不单单指的是整棵树的根节点)
TreeNode rootNode = new TreeNode(pre[preStart]);
//获得根节点在中序遍历的下标位置
int location = 0;
for (int i = midStart; i <= midEnd ; i++) {
if (mid[i]==rootNode.val){
location = i;
}
}
//两者的偏移量(计算左子树有几个几点几点树减一就是偏移量)
int offSet = location - midStart - 1;
//递归获得当前节点的左孩子
TreeNode left = creatBinaryTreeByPreMid(pre, preStart + 1, preStart+offSet+1, mid, midStart,midStart + offSet);
TreeNode right = creatBinaryTreeByPreMid(pre, preStart + offSet + 2, preEnd, mid, location + 1, midEnd);
rootNode.left = left;
rootNode.right = right;
return rootNode;
}
}