Split a binary search Tree
Asked Answered
M

3

7

Given a BST tree, we have to break the tree depending on the input(N), into two subtrees, where subtree1 consists of all the nodes, which are less than or equal to N and subtree2 consists of all the nodes which are greater than N.

          50
     /        \
     40         60
  /    \        /
 30     45     55
                 \
                  58

output:

       50
      /                               
     40          
   /    \         
 30     45


     60

    /

   55

     \

       58

I have come up with following algorithm but its not working correctly:

static Node splitTree(Node root, Node root2, int k){
    if(root == null)
        return null;

    while(root != null){
        if(root.data > k)
            root = root.left;
        else if(root.data < k)
            root = root.right;
        else
        {
            root2=root.right;
            root.right=null;
            break;
        }

    }
        return root2;


}
Myxoma answered 3/5, 2017 at 6:45 Comment(8)
what is the error or output you are getting and expected output you require ?Clemence
this solution is working fine only if the root node is equal to input n.for example : preorder of tree :50,40,30,35,60,55,58 and N =50, than it gives correct output i.e, Preorder Tree1 :50,40,30,45 and tree2 :60,55,58Myxoma
have you referred here quiz.geeksforgeeks.org/… or algolist.net/Data_structures/Binary_search_tree/Insertion these are pretty good explinations of how to implement/insert and search through BSTClemence
yes i have referred to them, in this question we have to split the tree even if N is not present in the tree.Myxoma
which language is it written in ??Candlefish
It is written in java.Myxoma
Can you please tag your question with java?Sissified
@Sissified Done sirMyxoma
S
8

You would not need the root2 argument, since that is the result of the function, and whatever value would be passed would be overwritten anyway.

The algorithm to split would in general not only need to cut an edge (making two trees), but also repeat this at deeper levels of the cut-off tree, since there may be subtrees there that should be attached at the place the cut-off happened.

For instance, if your tree looks like this:

                              16  
               +---------------+---------------+
               8                              24
       +-------+-------+               +-------+-------+
       4              12              20              28
   +---+---+       +---+---+       +---+---+       +---+---+
   2       6      10      14      18      22      26      30
 +-+-+   +-+-+   +-+-+   +-+-+   +-+-+   +-+-+   +-+-+   +-+-+
 1   3   5   7   9  11  13  15  17  19  21  23  25  27  29  31

And you want to cut with k = 11, then the two trees would look like this:

               8
       +-------+-------+
       4              10
   +---+---+       +---+---+
   2       6       9      11
 +-+-+   +-+-+     
 1   3   5   7      

                              16  
               +---------------+---------------+
              12                              24
               +-------+               +-------+-------+
                      14              20              28
                   +---+---+       +---+---+       +---+---+
                  13      15      18      22      26      30
                                 +-+-+   +-+-+   +-+-+   +-+-+
                                17  19  21  23  25  27  29  31

Note how there are several edges that were cut and replaced: 16-8 is replaced with 16-12, and 8-12 is replaced with 8-10. This can repeat several times, and corresponds to the number side-switches (between left and right) one has to make to find the (place for the) target value in the tree.

Suggested code:

static void setChild(Node node, boolean toLeft, Node child){
    // Assign child node to the indicated direction: left or right
    if (toLeft) {
        node.left = child;
    } else {
        node.right = child;
    }
}

static Node splitTree(Node root, int k){
    Node root2 = null;
    Node parent1 = null;
    Node parent2 = null;
    // Determine at which side of the root we will travel
    boolean toLeft = root != null && k < root.data;

    while (root != null) {
        while (root != null && (k < root.data) == toLeft) {
            parent1 = root;
            root = toLeft ? root.left : root.right;
        }
        setChild(parent1, toLeft, null); // Cut out the edge. root is now detached
        toLeft = !toLeft; // toggle direction
        if (root2 == null) {
            root2 = root; // This is the root of the other tree.
        } else if (parent2 != null) {
            setChild(parent2, toLeft, root); // re-attach the detached subtree
        }
        parent2 = parent1;
        parent1 = null;
    }
    return root2;
}
Sissified answered 3/5, 2017 at 9:4 Comment(6)
what if root.data < k && direction ==right, than inner while loop will not run for first time and parent1 will still be null , so parent1[direction] = null will throw an null pointer exception.Myxoma
This should not happen: direction is initialised with a value so that the inner loop will run at least once, and that loop will only exit when k < root.data is no longer true. This means that if there is a next iteration of the outer loop, the inner loop is guaranteed to run again at least one time (the direction has toggled). Did you have a case of a null pointer exception there?Sissified
if N=31, than direction will be right and k > root.data for the very first case only,so parent1 will still be null.Myxoma
Did you actually run it? If k > root.data and direction == 'right' then the inner while loop will not exit, so parent1 will be non-null. Note that the while condition will then be root != null && (false) == (false) which is true.Sissified
I updated the code a bit so the string direction is now a boolean toLeft. This should run without errors.Sissified
You're welcome ;-) Depending on what you want, you might need to replace k < root.data with k <= root.data, although the latter is less standard.Sissified
S
1

We can do the problem simply with recursion.

We create a function that returns pair of nodes to the required split trees

class pair{
    node small, big;
}

Our function looks like this pair splitBST(node root, int k)

Algo:

1   //check if root is null, both trees are empty
    if (root == null) 
        return pair(null, null)

2   //check if root.data > k. In this case we know that nodes smaller than k lies in left subtree since it's given that we have BST
    //Also, root will become part of pair.big
    if (root.data > k)
        pair leftAns = splitBST(root.left, k)
        //this contains two trees-small and big where big needs to be updated as there might be nodes in left subtree that are greater than k
        root.left = leftAns.big
        leftAns.big = root
        return leftAns

3   //for all other cases, we have to scan right subtree. This time root will become part of pair.small
        pair rightAns = splitBST(root.right, k)
        root.right = rightAns.small 
        rightAns.small = root
        return rightAns

Note: While thinking recursive solution, ALWAYS assume that my function returns the correct answer in all cases; don't think HOW it does so.

Stercoricolous answered 7/5, 2017 at 2:58 Comment(0)
C
1
public TreeNode[] splitBST(TreeNode root, int V) {
  if (root == null) {
      return new TreeNode[] { null, null };
  }

  if (root.val > V) {
     TreeNode[] l = splitBST(root.left, V);
     root.left = l[1];
     return new TreeNode[] { l[0], root };
  } else {
    TreeNode[] r = splitBST(root.right, V);
    root.right = r[0];
    return new TreeNode[] { root, r[1] };
  }
}
Canticle answered 4/2, 2018 at 6:42 Comment(2)
Please can you explain this solution a bit?Myxoma
@amrendersingh Because this recursive function will always return TreeNode[0] and TreeNode[1], TreeNode[0] will be the result that node value <= V and TreeNode[1] will contains all the node that value > V.Canticle

© 2022 - 2024 — McMap. All rights reserved.