序列化和反序列化二叉树 -----前序,中序,后序,层序

目录

一.序列化和反序列化

1.什么是序列化和反序列化

二.前序遍历

1.序列化

1.问题分析

2.代码实现

2.反序列化

1.问题分析

2.代码实现

三.后序遍历

1.序列化

1.思路分析

2.代码实现

2.反序列化

1.思路分析

2.代码实现

四.中序遍历

1.序列化

1.思路分析

2.代码实现

2.反序列化

1.思路分析

5.层序遍历

1.序列化

1.思路分析

2.代码实现

2.反序列化

1.思路分析

2.代码实现


一.序列化和反序列化

1.什么是序列化和反序列化

序列化(Serialization)是将对象转化为字节序列的过程,方便数据在网络传输和存储过程中的传递。在序列化过程中,对象的状态信息被转换为可以存储或传输的格式(如字节数组、XML、JSON等),以便在需要时能够将其反序列化为原始对象。序列化可以用于在不同的系统之间传输对象,或者将对象存储到磁盘上等。

反序列化(Deserialization)则是将序列化后的字节流还原成对象的过程,即恢复原始的对象状态信息。在反序列化过程中,可以根据序列化时使用的格式,将字节流转换成原始对象,使得原本序列化的对象状态得以恢复。

序列化和反序列化可以使得对象的状态信息在不同的应用程序或系统之间传输或存储变得更加容易和可靠。

我们这里的序列化就是将树对象转化为字符串,反序列化就是将字符串重新转换为树对象

二.前序遍历

1.序列化

1.问题分析

我们先根据前序遍历将树转换为一个字符串,其实很简单,就是一个前序遍历,加上字符串的拼接操作,例如现在题目有如下要求,根据前序遍历将树转换为字符串,空节点用'#'代替,相邻结点用','分割开

例如上图的二叉树,我们序列化成为字符串应该为{2,1,#,6,#,#,3,#,#}

我们代码其实很好实现,这其实就是前序遍历,到空节点的是后拼接#即可

如果对前序,中序,后序,层序遍历不明白的,推荐看这篇文章的讲解:树的遍历方式(前中后,层序遍历,递归,迭代,Morris遍历)-----直接查询代码_允歆辰丶的博客-CSDN博客

2.代码实现

    //前序遍历序列化
    public String preOrderSerialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        preOrderSerialize(root, sb);
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();

    }

    public void preOrderSerialize(TreeNode root, StringBuilder sb) {
        if (root == null) {
            sb.append("#" + ",");
            return;
        }
        sb.append(root.val + ",");
        preOrderSerialize(root.left, sb);
        preOrderSerialize(root.right, sb);

    }

2.反序列化

1.问题分析

我们如何根据字符串反序列化这棵树呢?其实递归的思路还是参考前序遍历.对于这个字符串data,每个结点都是","进行隔开的,而前序遍历的第一个元素就是根结点(关键也在于找到每一颗子树的根结点),因此我们字符串从前到后遍历,这样一层层的构建结点,然后递归后来的时候进行连接,整个二叉树就构建成功了,看下面这个图会更容易的理解为什么这样进行递归

2.代码实现

    //前序遍历反序列化
    public TreeNode preOrderDeserialize(String data) {
        String[] split = data.split(",");
        return preOrderDeserialize(split);

    }

    int index = 0;

    public TreeNode preOrderDeserialize(String[] nodes) {
        if (index >= nodes.length) {
            return null;
        }
        String node = nodes[index++];
        if (node.equals("#")) {
            return null;
        }
        //根
        TreeNode root = new TreeNode(Integer.parseInt(node));
        //左
        root.left = preOrderDeserialize(nodes);
        //右
        root.right = preOrderDeserialize(nodes);
        return root;

    }

三.后序遍历

1.序列化

1.思路分析

还是这颗二叉树,根据后序遍历的顺序,也是很容易就可以写出代码

这后序遍历序列化的字符串应该为:{#,#,#,6,1,#,#,3,2};

2.代码实现

    //后序遍历序列化
    public String postOrderSerialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        postOrderSerialize(root, sb);
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();

    }

    public void postOrderSerialize(TreeNode root, StringBuilder sb) {
        if (root == null) {
            sb.append("#" + ",");
            return;
        }
        postOrderSerialize(root.left, sb);
        postOrderSerialize(root.right, sb);
        sb.append(root.val + ",");

    }

2.反序列化

1.思路分析

后序遍历的反序列化和前序遍历的反序列化还是有一定的不同的,但大致的思路是一样的,就是寻找根节点的位置,然后递归一步步的建立二叉树,根据后序遍历的特点,我们得知这棵树的根结点在字符串最后的位置,然后将index前移,这个时候我们可以照抄前序遍历反序列化的代码了吗?当然不是,我们根据下面这个图可以很清楚的看到,root结点的前边是右子树的结点,因此我们应该先建立右子树,然后再建立左子树.

2.代码实现

    //后序遍历反序列化
    public TreeNode postOrderDeserialize(String data) {
        String[] split = data.split(",");
        index2 = split.length - 1;
        return postOrderDeserialize(split);

    }

    int index2;

    public TreeNode postOrderDeserialize(String[] nodes) {
        if (index2 < 0) {
            return null;
        }
        String node = nodes[index2--];
        if (node.equals("#")) {
            return null;
        }
        //根
        TreeNode root = new TreeNode(Integer.parseInt(node));
        //左
        root.right = postOrderDeserialize(nodes);
        //右
        root.left = postOrderDeserialize(nodes);
        return root;

    }

四.中序遍历

1.序列化

1.思路分析

和上面两题的思路一样,根据中序遍历的顺序,完成中序遍历的序列化

还是上面的树,中序遍历的序列化答案应该是为:{#,1,#,6,#,2,#,3,#};

2.代码实现

    //中序遍历序列化
    public String infixOrderSerialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        infixOrderSerialize(root, sb);
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();

    }

    public void infixOrderSerialize(TreeNode root, StringBuilder sb) {
        if (root == null) {
            sb.append("#" + ",");
            return;
        }
        infixOrderSerialize(root.left, sb);
        sb.append(root.val + ",");
        infixOrderSerialize(root.right, sb);

    }

2.反序列化

1.思路分析

中序遍历无法进行反序列化,我们在这里可以思考一下原因,在前序遍历和后序遍历的反序列化中,我们最主要的步骤就是找根结点,而在中序遍历的字符串中,我们无法确定根结点的位置,因此我们不能进行反序列化

5.层序遍历

1.序列化

1.思路分析

层序遍历其实就是借助队列来进行序列化,和层序遍历一样,一层一层的,只不过遇到非空节点,我们需要添加到队列中,因为在进行序列化的时候,空节点默认转换为"#",如果出队列的元素为null的时候,我们添加这个元素,并且进行continue操作.

层序遍历的序列化结果为:{2,1,3,#,6,#,#,#,#};

2.代码实现

    public String levelOrderSerialize(TreeNode root) {
        StringBuilder sb = new StringBuilder();
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode pop = queue.pop();
            if (pop == null) {
                sb.append("#" + ",");
                continue;
            }
            sb.append(pop.val + ",");
            queue.offer(pop.left);
            queue.offer(pop.right);

        }
        sb.deleteCharAt(sb.length() - 1);        
        return sb.toString();

    }

2.反序列化

1.思路分析

反序列化的思路其实和序列化的思路还是很像的,每一次找到根结点,然后将左右节点入队列,依次进行下去就可以了.

2.代码实现

    public TreeNode levelOrderDeserialize(String data) {
        String[] nodes = data.split(",");
        if (nodes[0].equals("#")) {
            return null;
        }
        int index = 1;
        TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode parent = queue.pop();
            if (nodes[index].equals("#")) {
                parent.left = null;
            } else {
                parent.left = new TreeNode(Integer.parseInt(nodes[index]));
                queue.offer(parent.left);
            }
            index++;
            if (nodes[index].equals("#")) {
                parent.right = null;
            } else {
                parent.right = new TreeNode(Integer.parseInt(nodes[index]));
                queue.offer(parent.right);

            }
            index++;
        }

        return root;
        
    }

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论
很高兴为您提供帮助!下面是 C 语言中基于前序中序序列构建二叉树的代码: ```c #include <stdio.h> #include <stdlib.h> #define MAXSIZE 1000 // 定义数组最大容量 int preOrder[MAXSIZE], inOrder[MAXSIZE]; // 定义前序序列和中序序列 typedef struct BinaryTree { int data; struct BinaryTree *left; // 左子树指针 struct BinaryTree *right; // 右子树指针 }BTNode, *BiTree; // 通过前序中序序列构建二叉树 BiTree BuildTree(int preBegin, int preEnd, int inBegin, int inEnd) { int i, j, rootValue; BiTree root; if (preBegin > preEnd || inBegin > inEnd) // 序列为空的情况 { return NULL; } rootValue = preOrder[preBegin]; // 根节点 root = (BiTree)malloc(sizeof(BTNode)); root->data = rootValue; for (i = inBegin; i <= inEnd; i++) // 找到根节点在中序序列中的位置 { if (inOrder[i] == rootValue) { break; } } int leftLen = i - inBegin; // 左子树长度 int rightLen = inEnd - i; // 右子树长度 root->left = BuildTree(preBegin + 1, preBegin + leftLen, inBegin, i - 1); // 递归构建左子树 root->right = BuildTree(preEnd - rightLen + 1, preEnd, i + 1, inEnd); // 递归构建右子树 return root; } // 输出后序序列 void postOrderTraversal(BiTree root) { if (root == NULL) // 如果遍历到为空的子树,直接返回 { return; } postOrderTraversal(root->left); // 递归输出左子树 postOrderTraversal(root->right); // 递归输出右子树 printf("%d ", root->data); // 输出根节点 } // 输出层序序列 void levelOrderTraversal(BiTree root) { BiTree queue[MAXSIZE]; int front = -1, rear = -1; // 初始化队头队尾指针 if (root == NULL) // 二叉树为空的情况 { return; } queue[++rear] = root; while (front != rear) { BiTree temp = queue[++front]; printf("%d ", temp->data); if (temp->left != NULL) { queue[++rear] = temp->left; } if (temp->right != NULL) { queue[++rear] = temp->right; } } } int main() { int n, i; // 输入节点数量 printf("请输入节点数量:"); scanf("%d", &n); // 输入前序中序序列 printf("请输入前序序列:"); for (i = 0; i < n; i++) { scanf("%d", &preOrder[i]); } printf("请输入中序序列:"); for (i = 0; i < n; i++) { scanf("%d", &inOrder[i]); } BiTree root = BuildTree(0, n - 1, 0, n - 1); // 输出后序序列 printf("后序序列为:"); postOrderTraversal(root); printf("\n"); // 输出层序序列 printf("层序序列为:"); levelOrderTraversal(root); printf("\n"); return 0; } ``` 注意:由于涉及二叉树的建立,本代码不支持输入非法序列。如果输入的前序中序序列无法构建二叉树,程序将崩溃或出现异常结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

允歆辰丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值