Want to save binary tree to disk for “20 questions” game

后端 未结 8 2015

In short, I\'d like to learn/develop an elegant method to save a binary tree to disk (a general tree, not necessarily a BST). Here is the description of my problem:

I\'

相关标签:
8条回答
  • 2021-02-06 15:33

    A simple way to accomplish this is to traverse the tree outputting each element as you do so. Then to load the tree back, simply iterate through your list, inserting each element back into the tree. If your tree isn't self balancing, you may want to reorder the list in such a way that the final tree is reasonably balanced.

    0 讨论(0)
  • 2021-02-06 15:33

    Here is the C++ code using PreOrder DFS:

    void SaveBinaryTreeToStream(TreeNode* root, ostringstream& oss)
    {
        if (!root)
        {
            oss << '#';
            return;
        }
    
        oss << root->data;
        SaveBinaryTreeToStream(root->left, oss);
        SaveBinaryTreeToStream(root->right, oss);
    }
    TreeNode* LoadBinaryTreeFromStream(istringstream& iss)
    {
        if (iss.eof())
            return NULL;
    
        char c;
        if ('#' == (c = iss.get()))
            return NULL;
    
        TreeNode* root = new TreeNode(c, NULL, NULL);
        root->left  = LoadBinaryTreeFromStream(iss);
        root->right = LoadBinaryTreeFromStream(iss);
    
        return root;
    }
    

    In main(), you can do:

    ostringstream oss;
    root = MakeCharTree();
    PrintVTree(root);
    SaveBinaryTreeToStream(root, oss);
    ClearTree(root);
    cout << oss.str() << endl;
    istringstream iss(oss.str());
    cout << iss.str() << endl;
    root = LoadBinaryTreeFromStream(iss);
    PrintVTree(root);
    ClearTree(root);
    
    /* Output:
                   A
    
           B               C
    
       D               E       F
    
         G           H   I
    ABD#G###CEH##I##F##
    ABD#G###CEH##I##F##
                   A
    
           B               C
    
       D               E       F
    
         G           H   I
     */
    

    The DFS is easier to understand.

    *********************************************************************************
    

    But we can use level scan BFS using a queue

    ostringstream SaveBinaryTreeToStream_BFS(TreeNode* root)
    {
        ostringstream oss;
    
        if (!root)
            return oss;
    
        queue<TreeNode*> q;
        q.push(root);
    
        while (!q.empty())
        {
            TreeNode* tn = q.front(); q.pop();
    
            if (tn)
            {
                q.push(tn->left);
                q.push(tn->right);
                oss << tn->data;
            }
            else
            {
                oss << '#';
            }
        }
    
        return oss;
    }
    TreeNode* LoadBinaryTreeFromStream_BFS(istringstream& iss)
    {
        if (iss.eof())
            return NULL;
    
        TreeNode* root = new TreeNode(iss.get(), NULL, NULL);
        queue<TreeNode*> q; q.push(root); // The parents from upper level
        while (!iss.eof() && !q.empty())
        {
            TreeNode* tn = q.front(); q.pop();
    
            char c = iss.get();
            if ('#' == c)
                tn->left = NULL;
            else
                q.push(tn->left = new TreeNode(c, NULL, NULL));
    
            c = iss.get();
            if ('#' == c)
                tn->right = NULL;
            else
                q.push(tn->right = new TreeNode(c, NULL, NULL));
        }
    
        return root;
    }
    

    In main(), you can do:

    root = MakeCharTree();
    PrintVTree(root);
    ostringstream oss = SaveBinaryTreeToStream_BFS(root);
    ClearTree(root);
    cout << oss.str() << endl;
    istringstream iss(oss.str());
    cout << iss.str() << endl;
    root = LoadBinaryTreeFromStream_BFS(iss);
    PrintVTree(root);
    ClearTree(root);
    
    /* Output:
                   A
    
           B               C
    
       D               E       F
    
         G           H   I
    ABCD#EF#GHI########
    ABCD#EF#GHI########
                   A
    
           B               C
    
       D               E       F
    
         G           H   I
     */
    
    0 讨论(0)
  • 2021-02-06 15:34

    I would store the tree like this:

    <node identifier>
    node data
    [<yes child identfier>
      yes child]
    [<no child identifier>
      no child]
    <end of node identifier>
    

    where the child nodes are just recursive instances of the above. The bits in [] are optional and the four identifiers are just constants/enum values.

    0 讨论(0)
  • 2021-02-06 15:35

    Not sure it's elegant, but it's simple and explainable: Assign a unique ID to each node, whether stem or leaf. A simple counting integer will do.

    When saving to disk, traverse the tree, storing each node ID, "yes" link ID, "no" link ID, and the text of the question or answer. For null links, use zero as the null value. You could either add a flag to indicate whether question or answer, or more simply, check whether both links are null. You should get something like this:

    1,2,3,"Does it have wings?"
    2,0,0,"a bird"
    3,4,0,"Does it purr?"
    4,0,0,"a cat"
    

    Note that if you use the sequential integers approach, saving the node's ID may be redundant, as shown here. You could just put them in order by ID.

    To restore from disk, read a line, then add it to the tree. You will probably need a table or array to hold forward-referenced nodes, e.g. when processing node 1, you'll need to keep track of 2 and 3 until you can fill in those values.

    0 讨论(0)
  • 2021-02-06 15:35

    In java if you were to make a class serializeable you can just write the class object to disc and read it back using input/output streams.

    0 讨论(0)
  • 2021-02-06 15:36

    You can store it recursively:

     void encodeState(OutputStream out,Node n) {
            if(n==null) {
                out.write("[null]");
            } else {
               out.write("{");
               out.write(n.nodeDetails());
               encodeState(out, n.yesNode());
               encodeState(out, n.noNode());
               out.write("}");
            }
      }
    

    Devise your own less texty output format. I'm sure I don't need to describe the method to read the resulting output.

    This is depth-first traversal. Breadth-first works too.

    0 讨论(0)
提交回复
热议问题