Serialize and Deserialize N-ary tree in Java

Serialize and Deserialize N-ary tree in java


This is a popular interview question asked in Tier-1 companies.

Given an n-ary tree, serialize and deserialize it.

Example of N-ary tree Serialization-Deserialization.

Serialize and Deserialize N-ary Tree

Algorithm


Serialization and Deserialization of N-ary tree is very similar to Serialization and Deserialization of Binary tree.

I would recommend to visit the Serialization/Deserialization post if not visited before: Serialize and Deserialize a Binary Tree

In Binary tree since there are only 2 child, we can get where is the start and end of the child of a particular Node from the serailized key, but in N-ary tree a Node can have n children, so we need some method to identify the start and end of a child nodes.

In this approach we will do a preorder traversal of N-ary tree and place the length of child nodes next to Node value as shown in example below,
 
serialize and deserialize n-ary tree implementation


In Deserialization process, it is exactly reverse now, we know first key in the String is the actual node and next key is the length of child nodes of a key.

Java Program to Serialize Deserialize N-ary tree


package javabypatel;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class SerializeDeserializeNAryTree {

    public static void main(String[] args) {
        NAryNode root = new NAryNode(1,
                Arrays.asList(
                        new NAryNode(2, Arrays.asList(
                                new NAryNode(5),
                                new NAryNode(6),
                                new NAryNode(7, Arrays.asList(
                                        new NAryNode(11),
                                        new NAryNode(12))))),
                        new NAryNode(3),
                        new NAryNode(4, Arrays.asList(
                                new NAryNode(8),
                                new NAryNode(9),
                                new NAryNode(10)))
                ));

        String str = serializeTree(root, new StringBuilder());
        System.out.println(str);
        NAryNode deserializeRoot1 = deserializeApproach1(str == null? null : str.split(","), new int[1]);
        NAryNode deserializeRoot2 = deserializeApproach2(str);

        System.out.println(deserializeRoot1);
        System.out.println(deserializeRoot2);
    }

    //In this approach, we need to take a separate index array of size 1 to remember the next element in array to pick
    //or we can take a static integer to remember the state.
    private static NAryNode deserializeApproach1(String[] arr, int[] index) {
        if (arr == null || index[0] >= arr.length || arr[index[0]] == null) {
            return null;
        }

        NAryNode n = new NAryNode(Integer.parseInt(arr[index[0]++]));
        int size = Integer.parseInt(arr[index[0]++]);
        n.child = new ArrayList<>(size);

        for (int i = 0; i < size; i++) {
            n.child.add(deserializeApproach1(arr, index));
        }
        return n;
    }

    //In this approach, we are converting serialized tree to Queue, so that when we do
    //queue.poll it will remove the element and we don't need to keep track of the next element to process.
    private static NAryNode deserializeApproach2(String str) {
        if (str == null) {
            return null;
        }
        return deserializeHelper(new LinkedList<String>(Arrays.asList(str.split(","))));
    }

    private static NAryNode deserializeHelper(Queue<String> queue) {
        if (queue.isEmpty()) {
            return null;
        }

        NAryNode n = new NAryNode(Integer.parseInt(queue.poll()));
        int size = Integer.parseInt(queue.poll());
        n.child = new ArrayList<>(size);

        for (int i = 0; i < size; i++) {
            n.child.add(deserializeHelper(queue));
        }
        return n;
    }

    private static String serializeTree(NAryNode root, StringBuilder sb) {
        if (root == null) {
            return null;
        }

        sb.append(root.data);
        sb.append(",");

        if (root.child != null) {
            sb.append(root.child.size());
            sb.append(",");
            for (int i = 0; i<root.child.size(); i++) {
                serializeTree(root.child.get(i), sb);
            }
        } else {
            sb.append(0);
            sb.append(",");
        }
        return sb.toString();
    }
}


NAryNode.java
package javabypatel;

import java.util.List;

public class NAryNode {
    public int data;
    public List<NAryNode> child;

    public NAryNode(int data, List<NAryNode> child) {
        this.data = data;
        this.child = child;
    }
    public NAryNode(int data) {
        this.data = data;
    }
}

N-ary tree preorder traversal in java

N-ary tree preorder traversal in java


This is a popular interview question asked in Tier-1 companies.

Given an n-ary tree, print preorder traversal of its nodes values.

Example of N-ary tree preorder traversal below:

n-ary tree preorder traversal example

Algorithm


Preorder traversal: To traverse a Binary Tree in Preorder, following operations are carried-out 
  1. Visit the root node and print data of that node. 
  2. Traverse the left subtree, and 
  3. Traverse the right subtree.

Preorder traversal of N-ary tree is very similar to that of Binary tree preorder traversal, only difference is instead of two children in Binary tree here we have N children.

Preorder traversal of Binary tree: Binary Tree Preorder Traversal

Considering the example above, 
we will first visit the root Node 1, then instead of directly going Left and then Right that is what we do in Binary tree preorder traversal because there is only 2 children, here we don't know the number of child, so what we are going to do is loop for all the child and then do a Preorder traversal for each child.
 
Visit Root Node 1
loop for all the children [Node 2, Node 3, Node 4]  (i = 0, i<3; i++) i=0

Visit Node 2, 
Iterate all its children [Node 5, Node 6, Node 7]  (i = 0, i<3; i++) i=0

Visit Node 5,
Iterate all its children []

Node 5 has no children so we came back to Node 2, now i = 1

Came back to Node 2, 
Iterate all its children [Node 5, Node 6, Node 7], (i = 0, i<3; i++), i =2 do for Node 6. 

and it continues.

Java Program to print N-ary tree preorder traversal


package javabypatel;

import java.util.Arrays;

public class NAryTreeTraversal {
    public static void main(String[] args) {
        NAryNode root = new NAryNode(1,
                Arrays.asList(
                        new NAryNode(2, Arrays.asList(
                                    new NAryNode(5),
                                    new NAryNode(6),
                                    new NAryNode(7, Arrays.asList(
                                                new NAryNode(11),
                                                new NAryNode(12))))),
                        new NAryNode(3),
                        new NAryNode(4, Arrays.asList(
                                    new NAryNode(8),
                                    new NAryNode(9),
                                    new NAryNode(10)))
                ));

        preOrderTraversal(root);
    }

    private static void preOrderTraversal(NAryNode start) {
        if (start == null) {
            return;
        }

        System.out.print(start.data + ",");
        if (start.child != null) {
            for (int i = 0; i < start.child.size(); i++) {
                preOrderTraversal(start.child.get(i));
            }
        }
    }
}

NAryNode.java
package javabypatel;

import java.util.List;

public class NAryNode {
    public int data;
    public List<NAryNode> child;

    public NAryNode(int data, List<NAryNode> child) {
        this.data = data;
        this.child = child;
    }
    public NAryNode(int data) {
        this.data = data;
    }
}

Custom BlockingQueue implementation in java

Producer Consumer using custom BlockingQueue implementation in java


Implement a custom Blocking Queue is very popular interview question.

What is Blocking Queue?

BlockingQueue is a queue data structure that blocks all the threads trying to read(Consumer) the data from the queue if the queue is empty and similarly it blocks all the threads trying to add(Producer) the data to the queue if the queue is full. due to this blocking feature, the queue is known as BlockingQueue. 

Threads that are blocked for adding the data to the queue due to queue full gets unblocked when some other thread removes the data from the queue and there is a space to add new data.

Threads that are blocked for reading the data from the queue due to queue empty gets unblocked when some other thread adds the data to the queue and there is some data to read.

Note: BlockingQueue doesn't accept null values, If we try to add null, then it throws NullPointerException.
Custom BlockingQueue implementation in java
Custom BlockingQueue implementation in java

I would recommend going through below articles for better understanding of Threads and synchronization in Java.


Implement Custom BlockingQueue in Java


 
package javabypatel;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class CustomBlockingQueueUsingLock {
    private Lock lock = new ReentrantLock();
    private Condition putCondition = lock.newCondition();
    private Condition takeCondition = lock.newCondition();

    private Object[] queue;
    private int queueSize;

    private int putIndex;
    private int takeIndex;
    private int count;

    public CustomBlockingQueueUsingLock(int queueSize) {
        this.queueSize = queueSize;
        queue = new Object[queueSize];
    }

    public void put(Object data) {
        lock.lock();
        try{
            while (count >= queueSize) {
                try {
                    putCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Queuing value :" + data);
            queue[putIndex] = data;
            count++;

            if (++putIndex >= queueSize) {
                putIndex = 0;
            }
            takeCondition.signalAll();
        }  finally {
            lock.unlock();
        }
    }

    public Object take() {
        lock.lock();
        try {
            while (count == 0) {
                try {
                    takeCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Object data = queue[takeIndex];
            count--;

            if (++takeIndex >= queueSize) {
                takeIndex = 0;
            }
            putCondition.signalAll();
            return data;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        CustomBlockingQueueUsingLock customBlockingQueue = new CustomBlockingQueueUsingLock(5);

        new Thread(() -> {
            int i = 0;
            while (i < 10) {
                System.out.println("data :" + customBlockingQueue.take());
                i++;
            }
        }, "Consumer Thread").start();

        new Thread(() -> {
            int i = 0;
            while (i < 10) {
                customBlockingQueue.put(i);
                i++;
            }
        }, "Producer Thread").start();
    }
}
 

Implement Custom Generic blocking queue using Linked list data structure and Locks in Java


package javabypatel;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class GenericCustomBlockingQueueUsingLock<T> {
    private Queue<T> queue = new LinkedList<T>();

    private Lock lock = new ReentrantLock();
    private Condition putCondition = lock.newCondition();
    private Condition takeCondition = lock.newCondition();

    private int size;

    public GenericCustomBlockingQueueUsingLock(int size) {
        this.size = size;
    }

    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                takeCondition.await();
            }
            T data = queue.poll();

            //If say the queue is full before we take, then chances are threads trying to put would be waiting, so after taking the
            //element we will inform put threads that there is space now for you to put.
            putCondition.signal();
            return data;
        } finally {
            lock.unlock();
        }
    }

    public void put(T obj) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == size) {
                putCondition.await();
            }
            System.out.println("Putting data :" + obj);
            queue.add(obj);

            //If say the queue is empty before we add the element to the queue, then chances are threads trying to take the element would be waiting,
            //so after adding the element we will inform take threads that there is element now for you to take.
            takeCondition.signal();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        GenericCustomBlockingQueueUsingLock<Integer> queue = new GenericCustomBlockingQueueUsingLock<>(10);
        new Thread(() -> {
            int i = 0;
            while (i < 20) {
                try {
                    System.out.println(queue.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i++;
            }
        }).start();

        new Thread(() -> {
            int i = 0;
            while (i < 20) {
                try {
                    queue.put(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i++;
            }
        }).start();
    }
}

Find length of the longest valid parenthesis substring

Find length of the longest balanced parenthesis in a string.


Given a string consisting of opening and closing parenthesis, find the length of the longest balanced parenthesis in it.

Lets see sample input and output for better understanding:
count longest valid parentheses length
longest valid parentheses count

Sort a Stack using Merge Sort

Sort a Stack using Merge Sort.


Lets see how to sort a stack using merge sort which uses divide and conquer recursive algorithm.

I recommend reading Merge sort first before proceeding.
Also, check Merge sort article on linked list that will help in understanding Merge sort and this article better.

Lets see sample input and output for better understanding:
sort a stack using recursion in java
Sort a Stack using Merge Sort in Java

Print path from root to a given node in a binary tree

Print path from root to a given node in a binary tree.


Given a Binary tree and a Key, Print a path from root to a key node.
Note: Given tree is Binary Tree and not Binary Search Tree.

Lets see sample input and output for better understanding:
Print path from root to given node in binary tree
Print path from root to given node in binary tree

Delete Middle Node of Linked List in Java

Delete Middle Node of Linked List in Java.


Given a linked list, Delete the middle node of linked list.

Lets see sample input and output for better understanding:

Remove duplicates from an unsorted linked list in Java.

Remove duplicates from an unsorted linked list in Java..


Given an unsorted linked list, Remove duplicates from it.

Lets see sample input and output for better understanding:

Check linked list is palindrome or not in java

Check linked list is palindrome or not in Java.


A palindromic number is a number that is the same when written forwards or backwards.

Lets see sample input and output for better understanding:

Find Running Median from a Stream of Integers

Find Running Median from a Stream of Integers in Java.


Given that integers are read from a data stream. Find median from the elements read so far in efficient way.

Lets see sample input and output for better understanding:

Find Moving Average of Last N numbers in a Stream.

Find Moving Average of Last N numbers in a Stream.


You are given a stream of numbers, calculate moving average of last N numbers in a stream.

In other words,
Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.

Lets see sample input and output for better understanding:

Find largest number in Binary Search Tree which is less than or equal to N

Largest number in Binary Search Tree which is less than or equal to N.


We have a binary search tree and a number N. Our goal is to find the greatest number in the binary search tree that is less than or equal to N. Print -1 if the the value of the element doesn't exists.

We have to find the largest number inside the binary search tree that is smaller than or equal to the target number N.

Lets see sample input and output:

Check if a Binary Tree is a Mirror Image or Symmetric in Java.

Check if a Binary Tree is a Mirror Image or Symmetric..


Check if a given binary tree is a symmetric or you can also say check whether tree is a mirror of itself (ie, symmetric around its center)

Lets see sample input and output:

Find Container with Most Water in Java

Find Container with Most Water.


Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.

Note: You cannot slant the container.

Lets understand what is the input and the expected output.

Check if a binary tree is subtree of another binary tree

Check if a binary tree is subtree of another binary tree.


Given two binary trees, check if the first tree is subtree of the second one. 
A tree is called subtree if all the nodes and its child of the subtree(S) is present in Tree(T) in the same structure.

Lets understand what is the input and the expected output.


Delete all occurrences of a given key in a linked list.

Delete all occurrences of a given key in a linked list.


Given a Linked list and key to delete, Remove all the occurrences of a given key in singly linked list.

Lets understand what is the input and the expected output.

Find K largest elements in array using Min Heap.

Find K largest elements in array using Min Heap.


Given a unsorted array, Find k largest element in array.

Find K largest elements in array using Max Heap

Lets understand what is the input and the expected output.


Find K largest elements in array using Max Heap

Find K largest elements in array using Max Heap.


Given a unsorted array, Find k largest element in array.

Heap Sort Algorithm

Lets understand what is the input and the expected output.


Quick Sort in Java

Quick Sort in Java.


Given a unsorted array, Sort it using Quick Sort Algorithm.

Merge sort linked list java

Lets understand what is the input and the expected output.

Reverse Level Order Traversal of Binary Tree Iteratively.

Reverse Level Order Traversal of Binary Tree in Java 


In this approach, we will use Stack and Queue for printing reverse level order traversal of Binary Tree. Let us first understand what we want to achieve? what is the input and what will be the expected output?