二叉树总结(序列化与反序列化)

二叉树总结(序列化与反序列化)

序列化(以先序为例,中序后序同理)

/**
 * 序列化二叉树(先序为例)
 * 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;
    }

}
    原文作者:HnuWyd
    原文地址: https://blog.csdn.net/HnuWyd/article/details/79781887
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞