每日一算法题-序列化二叉树

76 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

一、题目

描述:
请实现两个函数,分别用来序列化和反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出—棵与原二叉树相同的树。

image.png

#include<iostream>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    inline TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

char* serialize(TreeNode *root) {

}
TreeNode* deserialize(char *str) {

}

int main(int, char*[])
{
    TreeNode root(1);
    TreeNode node1(2);
    TreeNode node2(3);
    TreeNode node3(6);
    TreeNode node4(7);
    root.left = &node1;
    root.right = &node2;
    node2.left = &node3;
    node2.right = &node4;

    char* data = serialize(&root);
    TreeNode* node = deserialize(data);

    cout << node->val << endl;
    cout << node->left->val << endl;
    cout << node->right->val << endl;
    cout << node->right->left->val << endl;
    cout << node->right->right->val << endl;
}

二、分析

老规矩,对于动态申请内存的操作能避免则避免,题中规定节点数小于等于100,再加上叶子节点最多36个,每个叶子结点两个空子节点,也就是100+36*2=172,总共需要申请172的空间,但是如果考虑没有规定节点数的情况,本着兼容的原则,还是老老实实遍历获取总节点数吧。

题中规定数值不超过150,也就意味着我们最多使用1个字节就可以表示一个数,所以序列化的时候可以使用字节表示法,这样就可以避免使用逗号或者其他符号来讲数字隔开,也省去了分离的步骤,因为我们可以确定一个字节就是一个数,而空节点就可以使用151~255之间的数字来表示。

接着就是确定遍历顺序了,这里对于遍历顺序没有特殊注意的,先序中序后序皆可,因为我们是表示了空节点的,哪种顺序都能构建成功,但是从简单程度上来看,先序遍历会好一些,因为先序遍历每一步都是连上的,而中序和后序是有先构建子树再连接的情况,不利于逻辑推理。

三、模拟

  1. 1 "1"
  2. 1 -> 2 "12"
  3. 2 -> 空左 "12#"
  4. 2 -> 空右 "12##"
  5. 1 -> 3 "12##3"
  6. 3 -> 6 "12##36"
  7. 6 -> 空左 "12##36#"
  8. 6 -> 空右 "12##36##"
  9. 3 -> 7 "12##36##7"
  10. 7 -> 空左 "12##36##7#"
  11. 7 -> 空右 "112##36##7##"
  12. 遍历结束

四、实现

inline char toChar(int& i){
    return static_cast<char>(static_cast<unsigned char>(i));
}
inline int toInt(char& c){
    return static_cast<int>(static_cast<unsigned char>(c));
}
void serializeDfs(TreeNode *root, char* data, int& cursor) {
    static char none = static_cast<char>(static_cast<unsigned char>(151));
    if(root){
        data[cursor] = toChar(root->val);
        ++cursor;
        serializeDfs(root->left, data, cursor);
        serializeDfs(root->right, data, cursor);
    }else{
        data[cursor] = none;
        ++cursor;
    }
}
void serializeCount(TreeNode *root, int& count) {
    ++count;
    if(root){
        serializeCount(root->left, count);
        serializeCount(root->right, count);
    }
}
char* serialize(TreeNode *root) {
    int count = 0;
    if(root){
        serializeCount(root, count);
    }
    char* data = new char[count + 1];
    data[count] = 0;
    int cursor = 0;
    serializeDfs(root, data, cursor);
    return data;
}

TreeNode* deserializeDfs(char *str, int& cursor) {
    static char none = static_cast<char>(static_cast<unsigned char>(151));
    char& c = str[cursor];
    ++cursor;
    if(c == none) return nullptr;
    TreeNode* node = new TreeNode(toInt(c));
    node->left = deserializeDfs(str, cursor);
    node->right = deserializeDfs(str, cursor);
    return node;
}
TreeNode* deserialize(char *str) {
    if(!*str) return nullptr;
    int cursor = 0;
    return deserializeDfs(str, cursor);
}

五、结言

这道题主要还是对二叉树遍历算法在实际中的一种应用,熟练掌握基础算法很重要。

创作不易,留个赞再走吧!如果对文章内容有任何指正,欢迎评论!