拆分二叉搜索树

amr*_*ngh 5 java algorithm binary-search-tree data-structures

给定一个BST树,我们必须根据输入(N)将树分成两个子树,其中subtree1由所有节点组成,小于或等于N,而子树2由所有大于或等于N的节点组成. N.

          50
     /        \
     40         60
  /    \        /
 30     45     55
                 \
                  58
Run Code Online (Sandbox Code Playgroud)

输出:

       50
      /                               
     40          
   /    \         
 30     45


     60

    /

   55

     \

       58
Run Code Online (Sandbox Code Playgroud)

我已经提出了以下算法,但它无法正常工作:

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;


}
Run Code Online (Sandbox Code Playgroud)

tri*_*cot 6

你不需要root2参数,因为那是函数的结果,无论如何都会覆盖传递的任何值.

分割算法通常不仅需要切割边缘(制作两棵树),而且还要在截止树的更深层次重复这一点,因为那里可能存在应该附加在切割位置的子树 - 发生了.

例如,如果您的树看起来像这样:

                              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
Run Code Online (Sandbox Code Playgroud)

你想切割k = 11,然后两棵树看起来像这样:

               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
Run Code Online (Sandbox Code Playgroud)

注意如何切割和更换多个边缘:16-8用16-12替换,8-12用8-10替换.这可以重复几次,并且对应于在树中找到(放置)目标值的数字侧开关(在左和右之间).

建议代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

看它在repl.it上运行