• 二叉树的序列化和反序列化


    【说明】:

      本文是左程云老师所著的《程序员面试代码指南》第三章中“二叉树的序列化和反序列化”这一题目的C++复现。

      本文只包含问题描述、C++代码的实现以及简单的思路,不包含解析说明,具体的问题解析请参考原书。

      感谢左程云老师的支持。

    【题目】:

      二叉树被记录成文件的过程叫作二叉树的序列化,通过文件内容重建原来二叉树的过程叫做二叉树的反序列化。给定一颗二叉树的头节点 head,并已知二叉树节点值的类型为32位整形。请设计一种二叉树序列化和反序列化的方案,并用代码实现。

     【思路】:

      解法为先序遍历和层遍历两种。

    【编译环境】:

      CentOS6.7(x86_64)

      gcc 4.4.7

     【实现及测试】:

      声明代码:

    /*
     *文件名:bt_serial.h
     *作者:
     *摘要:实现二叉树的序列化和反序列化
     */
    
    #include <string>
    
    using namespace std;
    
    class Node
    {
    public:
        Node(int data)
        {
            value = data;
            left = NULL;
            right = NULL;
        }
    public:
        int value;
        Node *left;
        Node *right;
    };
    
    string serialByPre(Node *root); //通过先序遍历序列化为字符串
    Node* reconByPreString(string preStr); //将通过先序遍历序列化得到的的字符串反序列化
    
    string serialByLevel(Node *root);    //按层遍历序列化
    Node* reconByLevelString(string levelStr);//根据层遍历反序列化
    View Code

      实现及测试代码:

    /*
     *文件名:bt_serial.cpp
     *作者:
     *摘要:二叉树序列化与反序列化的实现
     */
     
    
    #include "bt_serial.h"
    #include <queue>
    #include <sstream>
    #include <iostream>
    
    //字符串转换为整形
    int strToint(string &svalue)
    {
        stringstream ss;
        ss << svalue;
        int ivalue;
        ss >> ivalue;
        return ivalue;
    }
    
    //整形转换为字符串
    string intTostr(int &ivalue)
    {
        stringstream ss;
        ss << ivalue;
        string svalue;
        ss >> svalue;
        return svalue;
    }
    
    string serialByPre(Node *root)
    {
        if(NULL == root)
            return "#!";
    
        string svalue = intTostr(root->value);
    
        string res = svalue + "!";
        res += serialByPre(root->left);
        res += serialByPre(root->right);
        return res;
    }
    
    Node* reconPreOrder(queue<string> *q)
    {
        string svalue = q->front();
        q->pop();
    //    cout << svalue << endl;
        if("#" == svalue)
            return NULL;
        
        int ivalue = strToint(svalue);
        
        Node *root = new Node(ivalue);
        root->left=reconPreOrder(q);
        root->right=reconPreOrder(q);
        return root;
    }
    
    Node* reconByPreString(string preStr)
    {
        size_t firPos = 0;
        size_t secPos = 0;
        queue<string>* q = new queue<string>;   //注意指针的使用
        
        secPos = preStr.find("!");
        while(secPos != string::npos)
        {
            q->push(preStr.substr(firPos, secPos - firPos));
            firPos = secPos + 1;
            secPos = preStr.find("!", firPos);
        }
    
        return reconPreOrder(q);
    }
    
    string serialByLevel(Node* root)
    {
        if(NULL == root)    
            return "#!";
        
        string svalue = intTostr(root->value);
        
        string res = svalue + "!";
        queue<Node*> q;
        q.push(root);
    
        while(!q.empty())
        {
            root = q.front();
            q.pop();
    
            if(NULL != root->left)
            {
                svalue = intTostr(root->left->value);
                res += svalue + "!";
                q.push(root->left);
            }
            else
            {
                res += "#!";
            }
            
            if(NULL != root->right)
            {
                svalue = intTostr(root->right->value);
                res += svalue + "!";
                q.push(root->right);
            }
            else
            {
                res += "#!";
            }
        }
        return res;    
    }
    
    Node* generateNodeByString(string val)
    {    
        if("#" == val)
            return NULL;
        
        return new Node(strToint(val));
    }
    
    Node* reconByLevelString(string levelStr)
    {
        size_t firPos = 0;
        size_t secPos = levelStr.find("!");
        queue<string>* qStr = new queue<string>;   //注意指针的使用
        
        while(secPos != string::npos)
        {
            qStr->push(levelStr.substr(firPos, secPos - firPos));
        //    cout << qStr->back() << endl;
            firPos = secPos + 1;
            secPos = levelStr.find("!", firPos);
        }
    
           queue<Node*>* qNode = new queue<Node*>;   //注意指针的使用
        Node *root = generateNodeByString(qStr->front());
        qStr->pop();
        if (NULL != root)
            qNode->push(root);
        
        Node *node = NULL;
        while(!qNode->empty())
        {
            node = qNode->front();
            qNode->pop();
    
            if (NULL != node)
                cout << node->value << endl;
            else
                cout << "#" << endl;
    
            node->left = generateNodeByString(qStr->front());
            qStr->pop();
            node->right = generateNodeByString(qStr->front());
            qStr->pop();
            if(NULL != node->left)
                qNode->push(node->left);
            if(NULL != node->right)
                qNode->push(node->right);
        }    
        return root;
    }
    
    
    int main()
    {
        string str = "12!3!#!#!#!";
        Node *root = reconByPreString(str);
        string str1 = serialByPre(root);
        cout << str1 << endl;
    
        root = reconByLevelString(str);
        str1 = serialByLevel(root);
        cout << str1 << endl;
        return 0;
    }
    View Code

    说明:

      由JAVA代码转到C++代码,像字符串类、队列类的在使用上的差距比较大。但是整体的思路还是左老师在书中所提出的。

      

    注:

      转载请注明出处;

      转载请注明源思路来自于左程云老师的《程序员代码面试指南》。

  • 相关阅读:
    android开发布局三(微信布局)
    Android开发adb,SQLite数据库运用
    直线电机磁负荷、电负荷
    MIT公开课(一):电场和偶极子
    哈工大电气工程系硕士研究生入学复试——自动控制原理1、2章
    直线电机与旋转电机的区别
    Math类介绍
    Scala编辑器和IntelliJ IDEA开发环境配置
    减少cpu的方法
    AS内存清理,建议以及查找内存泄露的方法
  • 原文地址:https://www.cnblogs.com/PrimeLife/p/5504379.html
Copyright © 2020-2023  润新知