使用递归来根据给定的最小值和最大值修剪二叉树

时间:2012-03-20 05:24:39

标签: recursion binary-tree

正如标题所说,我必须根据给定的最小值和最大值修剪二叉树。每个节点存储一个值和一个左/右节点。我可以定义私有帮助器方法来解决这个问题,但是否则我可能不会调用该类的任何其他方法,也不会创建任何数据结构,如数组,列表等。

示例如下:

                           overallRoot
                         _____[50]____________________
                        /                             \
          __________[38]                _______________[90]
         /              \              /
    _[14]                [42]      [54]_____
   /     \                                  \
[8]       [20]                               [72]
          \                             /    \
               [26]                     [61]      [83]

trim(52, 65);

应该返回:

overallRoot
[54]
    \
     [61]

我尝试过的解决方案有三种方法:

public void trim(int min, int max) {
rootFinder(overallRoot, min, max);

}

第一个递归方法完美地找到新的根。

private void rootFinder(IntTreeNode node, int min, int max) {
if (node == null)
    return;

if (overallRoot.data < min) {
    node = overallRoot = node.right;
    rootFinder(node, min, max);

}

else if (overallRoot.data > max) {
    node = overallRoot = node.left;
    rootFinder(node, min, max);
}
else
    cutter(overallRoot, min, max);
}

第二种方法应该消除不在最小/最大范围内的任何其他节点,但它不会像我希望的那样工作。

private void cutter(IntTreeNode node, int min, int max) {
if (node == null)
    return;

if (node.data <= min) {
    node.left = null;
}
if (node.data >= max) {
    node.right = null;
}

if (node.data < min) {
    node = node.right;
}

if (node.data > max) {
    node = node.left;
}


cutter(node.left, min, max);
cutter(node.right, min, max);
}

返回:

overallRoot
[54]_____
         \
          [72]
         /
     [61]

感谢任何帮助。如果需要,请随时提出进一步的解释。

3 个答案:

答案 0 :(得分:2)

这假设节点x具有以下值:

  1. left(指向左侧孩子的指针)
  2. 右(指向正确孩子的指针)
  3. parent(指向父级的指针)
  4. 您可能想要创建一个名为CutBranch的方法,该方法只需从树中删除一个节点及其子树。让T成为你的树,让T.root成为指向它的根。它可以像这样工作:

    CutBranch(x,T) {
        y = T.root;
        while (y.left != x && y.right != x) {
            if (y < x) y = y.right;
            else       y = y.left;
            }
        if (y < x) y.right = Nil;
        else       y.left = Nil;
    }
    

    这假设您的树当然不包含具有相同值的节点,但它需要O(lg n)时间。但它不会进行任何垃圾收集。

    现在您可以遍历节点,每次到达小于下限的节点时,您可以在其左侧子节点上调用CutBranch,然后删除节点本身。如果节点大于你的上限,那么你可以CutBranch它是正确的孩子并删除它。

答案 1 :(得分:1)

很好的问题,竖起大拇指,虽然我认为如果你考虑采用不同的方法,它会变得更容易。就像,对于每个节点,首先“修剪”孩子,然后“TRIM”本身。

  1. 以下方法假定树是您问题中的示例的BST。

    public Node trim(Node root, int min, int max){
        if(root==null)
            return root;
        root.rightChild = trim (root.rightChild, min, max);
        root.leftChild = trim (root.leftChild,min,max);
    
        if(root.key>max || root.key<min){
            if(root.rightChild!=null)
                return root.rightChild;
            return root.leftChild;
        }
        return root;
    }
    
  2. 但是,如果您希望它适用于任何二叉树,请不要使用BST。只需对上面的if语句进行以下更改即可。

    if(root.key>max || root.key<min){
        if(root.rightChild==null)
            return root.leftChild;
        else if(root.leftChild==null)
            return root.rightChild;
        else{
            //randomly select one of the children to be parent and add the other child to the first free space in its sub tree
            //This is based on personal preferences
            Node temp = root.leftChild;
            while(temp.leftChild!=null || temp.rightChild!=null){
                temp = temp.leftChild;
            }
            if(temp.leftChild==null)
                temp.leftChild=root.rightChild;
            else
                temp.rightChild=root.rightChild;
            return root.leftChild;
        }
    } 
    
  3. 该方法应该像

    一样调用
    tree.root = trim(tree.root, min, max);
    

答案 2 :(得分:0)

使用树时,我发现最简单的方法是使用Node并返回Node的递归方法,我的想法是我可以调用方法来“更新”我下面的节点通过调用它们的方法。

在这种情况下,例如,您可以使用Node minBound(Node)返回此节点的子树,该子树位于下限之上。如果当前Node在绑定中,则递归地应用于每个子节点并返回自己。如果当前Node不在边界内,则以正确的方向返回更新的子Node。如果当前Nodenull,则只返回null

必须为maxBound编写等效方法。

然后你可以minBound(maxBound(root))来获取树的新根。

(您可以将minBoundmaxBound合并到一个方法中,但为了便于解释,我决定将它们分开。)

编辑:因为它已经很久了,我想我实际上已经放了一个代码样本来表明我的意思。

public void trim(int min, int max) {
  overallRoot = minBound(maxBound(overallRoot,max),min);
}

private IntTreeNode minBound(IntTreeNode node, int min) {
  if (node == null) // base case of our recursion
    return null;
  if (node.value < min) // we're too small, but our larger children might be in
    return minBound(node.right, min);
  // if we make it to here then we're in bounds, so update our left child
  // (our right child is bigger than us, so doesn't need to be processed)
  node.left = minBound(node.left, min);
  return node;
}

private IntTreeNode maxBound(IntTreeNode node, int max) {
  if (node == null) // base case of our recursion
    return null;
  if (node.value > max) // we're too big, but our smaller children might be in
    return maxBound(node.left, max);
  // if we make it to here then we're in bounds, so update our right child
  // (our left child is smaller than us, so doesn't need to be processed)
  node.right = maxBound(node.right, max);
  return node;
}