• LeetCode·297.二叉树的序列化与反序列化·DFS·BFS


    链接:https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/solution/by-xun-ge-v-dyrv/
    来源:力扣(LeetCode
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 

    题目

    示例

     

     

    思路

    解题思路
    对于树的相关问题递归基本上都可以解决,递归能解决的问题迭代基本上也可以解决
    所以对于本题有两种方向

    1. 递归->深度优先搜索

            深度优先搜索又可以分为

    •         先序遍历
    •         中序遍历
    •         后序遍历
    1. 迭代->广度优先搜索

            广度优先搜索

    •         层次遍历

    具体实现

    递归->深度优先搜索
    这里我们寻找先序遍历,因为先序遍历优先处理根节点,对于后序构造树比较方便
    遍历整个树元素,将对应树元素存储在字符串中,应当注意树元素为整型而存储在字符串中需要对其进行转换,对于空节点我们自定义 @ 表示,两个节点之间的数据用 , 隔开。
    反构造树,也是以先序遍历顺序,先构造根节点,然后构造左右节点

    迭代->广度优先搜索
    大体思路和递归差不多,根据树的层次遍历,访问树的节点,将树中节点存储在字符串数组中
    反构造时按层次遍历方向构造

    还有两种特殊解法看代码

    代码

    递归->深度优先搜索

    1. /**
    2. * Definition for a binary tree node.
    3. * struct TreeNode {
    4. * int val;
    5. * struct TreeNode *left;
    6. * struct TreeNode *right;
    7. * };
    8. */
    9. void dfs(struct TreeNode * root, char * str)
    10. {
    11. if(root == NULL)//空节点,用@代替
    12. {
    13. strcat(str, "@");
    14. strcat(str, ",");
    15. return;
    16. }
    17. char s[7] = "";//临时保存树元素值
    18. sprintf(s, "%d,", root->val);//类型转换
    19. strcat(str, s);//加入字符串数组中
    20. dfs(root->left, str);//递归遍历左右子节点
    21. dfs(root->right, str);
    22. return;
    23. }
    24. /** Encodes a tree to a single string. */
    25. char* serialize(struct TreeNode* root) {
    26. char * str = calloc(500000,sizeof(char));//申请额外空间。并对其初始化为0
    27. dfs(root, str);//先序遍历
    28. return str;
    29. }
    30. struct TreeNode * dfsTree(char * data, int * inode)//先序遍历反构造树
    31. {
    32. if(data[*inode] == '@')//空节点,构造
    33. {
    34. (*inode) += 2;跳过‘@和,’
    35. return NULL;
    36. }
    37. char s[7] = "";//临时保存元素值
    38. int node = 0;
    39. for(*inode; data[(*inode)] != ','; (*inode)++)//读取树元素值
    40. {
    41. s[node++] = data[*inode];
    42. }
    43. (*inode)++;//跳过‘,’
    44. struct TreeNode * root = malloc(sizeof(struct TreeNode));//构造节点
    45. root->val = atoi(s);//元素转换
    46. root->left = dfsTree(data, inode);//构造左右子节点
    47. root->right = dfsTree(data, inode);
    48. return root;
    49. }
    50. /** Decodes your encoded data to tree. */
    51. struct TreeNode* deserialize(char* data) {
    52. int inode = 0;
    53. return dfsTree(data, &inode);
    54. }
    55. // Your functions will be called as such:
    56. // char* data = serialize(root);
    57. // deserialize(data);
    58. 作者:xun-ge-v
    59. 链接:https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/solution/by-xun-ge-v-dyrv/
    60. 来源:力扣(LeetCode)
    61. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    迭代->广度优先搜索

    1. //BFS模拟传统层序遍历进行反序列化,即序列化使用层序遍历将二叉树的节点按顺序转换为字符串,反序列化先将字符串的值先转换为节点值,再将节点值按层序遍历的顺序反向生成二叉树
    2. #define queue_size 50000
    3. #define data_size 80000 //这个如果根据示例不同调整大小的话会节省空间
    4. //序列化函数,该函数时将二叉树转换为字符串,具体方法是层序遍历,利用队列先入先入先出的特点,将每一层的节点放入队列中,先将当前节点值拼接到字符中,再将数组中队列的下一层的左右子节点支放入队列中,不断轮询直到所有节点均写入字符中返回
    5. char* serialize(struct TreeNode* root){
    6. char* data=(char*)malloc(data_size*sizeof(char));
    7. data[0]='\0'; //为了方便后面使用strcat
    8. if(root==NULL){
    9. return data;
    10. }
    11. int head=0; //队列首
    12. int tail=0; //队列尾
    13. struct TreeNode* queue[queue_size];
    14. queue[tail++]=root;
    15. char temp[10];
    16. int flag=0; //用来标记是否是第一个字符
    17. while(head!=tail){
    18. //队首节点非空
    19. if(queue[head]!=NULL){
    20. //除了第一个位置不需要补','外,其余字符之间需要补上',',将','写入到结果字符串
    21. if(flag==1){
    22. strcat(data,",");
    23. }
    24. flag=1;
    25. sprintf(temp,"%d",queue[head]->val);
    26. strcat(data,temp);
    27. //当前节点的左右子节点入队
    28. queue[tail++]=queue[head]->left;
    29. queue[tail++]=queue[head]->right;
    30. }
    31. //队首节点为空
    32. else{
    33. //null字符输出到data
    34. strcat(data,",");
    35. strcat(data,"null");
    36. }
    37. //队列头部指针后移
    38. head++;
    39. }
    40. return data;
    41. }
    42. //反序列化函数,该函数时将字符串转换为二叉树,首先从字符串中提取所有节点值,再使用层序遍历,根据队列的情况,反向生成二叉树,思路是根据序列化函数判断,队列中的值是根据当前层序从左到右,不同层序从上到下的顺序放置,就将头指针定义为根节点,尾指针后移寻找左右子节点,根据头尾指针的情况,从上到下生成新的二叉树
    43. struct TreeNode* deserialize(char* data) {
    44. if(data[0]=='\0'){
    45. return NULL;
    46. }
    47. //将字符串读入数组
    48. int nums[queue_size]={0};
    49. int nums_pos=0; //从第1位开始写,转换成树的时候比较方便
    50. int data_pos=0;
    51. char temp[10];
    52. int temp_pos=0;
    53. while(data[data_pos]!='\0'){
    54. temp_pos=0;
    55. //当遇到','时直接跳过
    56. if(data[data_pos]==','){
    57. data_pos++;
    58. }
    59. //将节点值从字符串中提取出来,放入中间字符串中用于转换数字
    60. while(data[data_pos]!=','&&data[data_pos]!='\0'){
    61. temp[temp_pos]=data[data_pos];
    62. temp_pos++;
    63. data_pos++;
    64. }
    65. temp[temp_pos]='\0';
    66. //如果为空节点
    67. if(strcmp("null",temp)==0){
    68. nums[nums_pos]=INT_MIN;
    69. nums_pos++;
    70. }
    71. //如果节点非空
    72. else{
    73. //sscanf()函数作用时提取字符串中数据
    74. sscanf(temp,"%d",&nums[nums_pos]);
    75. nums_pos++;
    76. }
    77. }
    78. //将数组输出成树
    79. struct TreeNode* queue[queue_size]; //存储节点地址的队列
    80. //先生成根节点,以便返回结果
    81. struct TreeNode* root=(struct TreeNode*)malloc(sizeof(struct TreeNode));
    82. root->val=nums[0];
    83. root->left=NULL;
    84. root->right=NULL;
    85. queue[0]=root;
    86. int head=0; //队列首
    87. int tail=1; //队列尾
    88. int pos=1; //nums数组位置
    89. struct TreeNode* ret=root;
    90. //模拟树的层序遍历进行反向建树
    91. while(head!=tail){
    92. //如果节点不为空,从nums数组中读取两个元素
    93. if(queue[head]!=NULL){
    94. //左孩子
    95. struct TreeNode* left_child;
    96. //左孩子非空
    97. if(nums[pos]!=INT_MIN){
    98. left_child=(struct TreeNode*)malloc(sizeof(struct TreeNode));
    99. left_child->val=nums[pos];
    100. }
    101. //左孩子为空
    102. else{
    103. left_child=NULL;
    104. }
    105. queue[head]->left=left_child;
    106. queue[tail++]=left_child;
    107. pos++;
    108. //右孩子
    109. struct TreeNode* right_child;
    110. //右孩子非空
    111. if(nums[pos]!=INT_MIN){
    112. right_child=(struct TreeNode*)malloc(sizeof(struct TreeNode));
    113. right_child->val=nums[pos];
    114. }
    115. //左孩子为空
    116. else{
    117. right_child=NULL;
    118. }
    119. queue[head]->right=right_child;
    120. queue[tail++]=right_child;
    121. pos++;
    122. }
    123. //空不空都弹出队列首节点
    124. head++;
    125. }
    126. return ret;
    127. }
    128. 作者:xun-ge-v
    129. 链接:https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/solution/by-xun-ge-v-dyrv/
    130. 来源:力扣(LeetCode)
    131. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    还有两种特殊解法看代码

    1. //取巧解法,直接进行强制类型转换,将二叉树和字符串进行强制转换
    2. char* serialize(struct TreeNode* root) {
    3. return (char *)root;
    4. }
    5. struct TreeNode* deserialize(char* data) {
    6. return (struct TreeNode *)data;
    7. }
    8. 作者:xun-ge-v
    9. 链接:https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/solution/by-xun-ge-v-dyrv/
    10. 来源:力扣(LeetCode)
    11. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    1. //还可以通过全局变量
    2. struct TreeNode* hhh;
    3. char* serialize(struct TreeNode* root) {
    4. hhh=root;
    5. return "";
    6. }
    7. struct TreeNode* deserialize(char* data) {
    8. return hhh;
    9. }
    10. 作者:xun-ge-v
    11. 链接:https://leetcode.cn/problems/serialize-and-deserialize-binary-tree/solution/by-xun-ge-v-dyrv/
    12. 来源:力扣(LeetCode)
    13. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

     

  • 相关阅读:
    【校招VIP】产品深入分析之电商运营
    C51--开发环境
    第四章 网络层 | 计算机网络(谢希仁 第八版)
    docker-compose 安装 jekins
    十年架构五年生活-06 离职的冲动
    【数据结构】线性表相关操作(C++实现)
    (四)模型训练保存与加载
    Leetcode236 二叉树两节点的最近公共祖先
    MyBatis-----10、MyBatis逆向工程
    PHP代码审计14—变量覆盖
  • 原文地址:https://blog.csdn.net/m0_64560763/article/details/126263510