1

My question is a tiny bit different from the results I found, and I haven't used Java in quite a while (novice), so I need some clarification.

Basically, I'm pretty sure my implementation is mostly correct, I just wanted to give some back story to what I was doing.

So, my real problem is that I have serialized a binary tree to a string:

      1
   2     3
 4   5

as:

1 2 4 # # 5 # # 3 # #

where the # are just null nodes.

My problem comes when I'm trying to rebuild it from the string. I've been doing some digging for quite a few hours, but I think I'm overcomplicating it. I just need to know the simplest way to read the string as such (delimited by whitespace):

the first element is 1, so we will change that to an int and make a node with that as the element. The next is 2, so do the same, then 4. The next is a #, so we ignore that as there is no leaf, etc.

then, I need to send the remaining part of the string (minus what has already been read from the front) into a recursive call.

In summary, my question is basically "what's the easiest way to parse it as described, and send the remaining string into a recursive call?"

5 Answers 5

2

Below is my code to serialize a binary and deserialize a binary tree. We just dump the tree in preorder into a string. Here, I used code from Rahul, but I modified it to be more concise.

public class DeSerializationBinaryTree {
    public static String serialize(Node root) {
        if (root == null)
            return "# ";
        else {
            return root.val + " " + serialize(root.left) + serialize(root.right);
        }
    }

    public static Node deserialize(String res) {
        String[] tokens = res.trim().split("\\s+");
        return deserialize(tokens);
    }

    static int index = 0;

    private static Node deserialize(String[] stringArray) {
        if (index >= stringArray.length)
            return null;
        if (stringArray[index].equals("#")) {
            index++;
            return null;
        }

        int value = Integer.parseInt(stringArray[index]);
        Node tree = new Node(value);
        index++;
        tree.left = deserialize(stringArray);
        tree.right = deserialize(stringArray);
        return tree;
    }

    private static void inorder(Node root) {
        if (root != null) {
            inorder(root.left);
            System.out.println(root.val);
            inorder(root.right);
        }
    }

    public static void main(String[] args) {
        Node root = new Node(30);
        Node node1 = new Node(10);
        Node node2 = new Node(20);
        Node node3 = new Node(50);
        Node node4 = new Node(45);
        Node node5 = new Node(35);
        root.left = node1;
        root.right = node2;
        node1.left = node3;
        node2.left = node4;
        node2.right = node5;

        System.out.println(serialize(root));
        Node node = deserialize("30 10 50 # # # 20 45 # # 35 # # ");
        inorder(node);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I would use parentheses when serializing the tree to a string:

1(2(3 4) 5(6))

Describes the tree:

         1
       /   \
      /     \
     /       \
    2         5
   / \       / 
  /   \     /    
 3     4   6      

There is some ambiguity when you have just one child because you can't tell whether the child is a left or a right child. In that case you can have an explicit "no child" character:

1(2(3 4) 5(# 6))     //6 is the right child
1(2(3 4) 5(6 #))     //6 is the left child

So when parsing it, whenever you encounter an opening parenthesis you're looking at the children of the current node. When you encounter a closing parenthesis you know you're done with the children of that node and so you can fall back to the previous level.

2 Comments

The existing syntax is unambiguous if you interpret it as the OP describes in his question. It is basically a pre-order depth first traversal, outputting '#' each time a null is encountered.
@StephenC Yes, if you have a specified order of traversal then there is no ambiguity.
1

use this java method..consider you have string array...

private static Tree<Integer> deserialize(Tree<Integer> tree,
        String[] stringArray) {
    // TODO Auto-generated method stub
    if(index>=stringArray.length)
        return null;
    if(stringArray[index].equals("#")){
        index++;
        return null;

    }
    int value=Integer.parseInt(stringArray[index]);
    tree=new Tree<Integer>(value);
    index++;
    tree.left=deserialize(tree.left, stringArray);
    tree.right=deserialize(tree.right, stringArray);
    return tree;
}

Comments

0

I just need to know the simplest way to read the string as such (delimited by whitespace)

Create a Scanner from the String, and use hasInt() / nextInt() and next(). Something like this:

    Scanner s = new Scanner(inputString);
    s.setDelimiters("\\s+");
    ...

    if (s.hasInt()) {
        int = s.nextInt();
        // ... create a node and recurse twice to populate its children
    } else if (s.next().equals("#")) {
        // ... this is a null node
    } else {
        // ... syntax error
    }

Comments

0
private int index =0;  

/**
 * Saves this tree to a file.
 * @param filename the name of the file in which to save this tree; 
 *              if null, uses default file name
 * @return   <code>true</code> if successful save
 *          <code>false</code> otherwise
 * @throws IOException if unexpected IO error 
 */

public final boolean save(String filename) throws IOException{
    List<String> sbtList = new ArrayList<>();
    sbtList = preOrderSerialize(this, sbtList);
    for (String sbtList1 : sbtList) {
        System.out.println(sbtList1);
    }
    try{
        OutputStream file = new FileOutputStream (filename);
        OutputStream buffer = new BufferedOutputStream(file);
        output = new ObjectOutputStream(buffer);
        output.writeObject(sbtList);

    }catch (IOException e){
        System.err.println("Save not successful" + e);
        return false;
    }
    finally { 
        output.close(); 
    }
   return true;
}
/**
 * The pre-order traversal to serialize a binary tree
 * @param sbt
 * @return
 * @throws IOException 
 */
private List<String> preOrderSerialize(StringBinaryTree sbt, List<String> myList){ 
    if (sbt == null){ 
        myList.add("# ");
    }           
    else{
        //sbt.add(this.value + "");
        myList.add(this.value + " ");
        preOrderSerialize(sbt.leftNode, myList);
        preOrderSerialize(sbt.rightNode, myList);
    }
   return myList;
}

/**
 * Restores this tree from a file. 
 * @param filename the name of the file from which to restore the tree;
 * if <code>null</code>, uses default file name.
 * @return <code>true</code> if successful restore
 *          <code>false</code> otherwise
 * @throws IOException if there is an IO issue
 */
public final boolean restore(String filename) throws IOException{
    try {
        InputStream file = new FileInputStream (filename);
        InputStream buffer = new BufferedInputStream (file);
        input = new ObjectInputStream(buffer);
        try{
            List <String> restoreSBT = (List<String>)input.readObject();
            StringBinaryTree root = deSerialize (restoreSBT);
        } finally {
            input.close();
        }
    }
    catch(IOException ex){
        System.err.println("File Not Restored" + ex);
        return false;
    }
    catch (ClassNotFoundException e){
        System.err.println("Cannot read file: Class Not Found"+ e);
        return false;
    }
    return true;
}

private StringBinaryTree deSerialize(List<String> restoreSBT ){
    if (index >= restoreSBT.size()){
        return null; 
    }
    if (restoreSBT.get(index).equals("#")){
        index ++;
        return null;
    }
    StringBinaryTree root = new StringBinaryTree (restoreSBT.get(index));
    index++;
    root.leftNode = deSerialize(restoreSBT);
    root.rightNode = deSerialize(restoreSBT);
    return root;
}

1 Comment

Code only answers arent allowed on Stackoverflow

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.