NOTE

序列化二叉树

记录使用先序遍历,以及先序遍历与中序遍历组合序列化和反序列化二叉树的方法。

Data Structures & Algorithms创建于 更新于 约 1 分钟读完historical

这是历史学习笔记,可能存在过时或不完整的理解。

1. 题目描述

请实现两个函数,分别用来序列化和反序列化二叉树

二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

2. 思路

  • 先序遍历
  • 先序遍历+中序遍历

3. 实现

3.1. 先序遍历

public class 序列化二叉树
{
    private static final String SHARP = "#";
    private static final String COMMA = ",";

    private Integer index = -1;

    String Serialize(TreeNode root)
    {
        //把遍历的结果保存到list中
        List<String> res = new ArrayList<>();
        if (root == null)
        {
            return String.join(COMMA, res);
        }

        //采用先序遍历,如果到达空节点,那么加入#
        this.preOrder(root, res);

        //把list转成string,中间用空格分隔
        return String.join(COMMA, res);
    }

    private void preOrder(TreeNode root, List<String> res)
    {
        //如果是空的节点那么使用#表示
        if (root == null)
        {
            res.add(SHARP);
            return;
        }

        res.add(String.valueOf(root.val));
        this.preOrder(root.left, res);
        this.preOrder(root.right, res);

    }

    TreeNode Deserialize(String str)
    {
        //检查参数
        if (str == null || str.length() == 0)
        {
            return null;
        }

        //str按照,切分成list
        String[] split = str.split(COMMA);
        //使用一个变量记录当前正在构造的节点
        return this.preOrderDeserialize(split);


    }

    private TreeNode preOrderDeserialize(String[] split)
    {
        index++;
        String val = split[index];
        if (!val.equals(SHARP))
        {
            //序列化用的先序遍历,那么反序列化也是用先序遍历
            TreeNode treeNode = new TreeNode(Integer.parseInt(val));
            treeNode.left = this.preOrderDeserialize(split);
            treeNode.right = this.preOrderDeserialize(split);
            return treeNode;
        }
        return null;
    }
}

3.2. 先序遍历+中序遍历

package main

import (
	"fmt"
	"strconv"
	"strings"
)

/*
 * type TreeNode struct {
 *   Val int
 *   Left *TreeNode
 *   Right *TreeNode
 * }
 */

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * @param root TreeNode类
 * @return TreeNode类
 */
func Serialize(root *TreeNode) *TreeNode {
	str := serialize(root)

	return deserialize(str)
}

func deserialize(str string) *TreeNode {
	datas := strings.Split(str, " ")
	pre := datas[:len(datas)/2]
	mid := datas[len(datas)/2:]

	return reConstruct(pre, mid)
}

func reConstruct(pre []string, vin []string) *TreeNode {
	if len(pre) == 0 || len(vin) == 0 {
		return nil
	}
	//从pre中找到root
	rootVal, _ := strconv.Atoi(pre[0])
	root := &TreeNode{
		Val: rootVal,
	}
	//用root把vin分成两半
	var i int
	for i = 0; i < len(vin); i++ {
		if vin[i] == pre[0] {
			break
		}
	}
	leftVin := vin[:i]
	rightVin := vin[i+1:]

	//也把pre分成两半
	leftPre := pre[1:i+1]
	rightPre := pre[i+1:]

	//左子树
	root.Left = reConstruct(leftPre, leftVin)
	//右子树
	root.Right = reConstruct(rightPre, rightVin)
	return root
}

func serialize(root *TreeNode) string {
	if root == nil {
		return ""
	}

	preOrderData := make([]int, 0)
	preOrder(root, &preOrderData)

	midOrderData := make([]int, 0)
	midOrder(root, &midOrderData)

	str := ""
	for _, data := range preOrderData {
		str += fmt.Sprintf("%v ", data)
	}

	for _, data := range midOrderData {
		str += fmt.Sprintf("%v ", data)
	}

	str = strings.TrimRight(str, " ")
	return str
}

func midOrder(root *TreeNode, midOrderData *[]int) {
	if root == nil {
		return
	}

	midOrder(root.Left, midOrderData)
	*midOrderData = append(*midOrderData, root.Val)
	midOrder(root.Right, midOrderData)
}

func preOrder(root *TreeNode, preOrderData *[]int) {
	if root == nil {
		return
	}

	*preOrderData = append(*preOrderData, root.Val)
	preOrder(root.Left, preOrderData)
	preOrder(root.Right, preOrderData)
}

4. 参考

讨论

使用 GitHub 账号参与讨论,评论会保存在 GitHub Issues 中。在 GitHub 查看