正如标题所说,我必须根据给定的最小值和最大值修剪二叉树。每个节点存储一个值和一个左/右节点。我可以定义私有帮助器方法来解决这个问题,但是否则我可能不会调用该类的任何其他方法,也不会创建任何数据结构,如数组,列表等。
示例如下:
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]
感谢任何帮助。如果需要,请随时提出进一步的解释。
答案 0 :(得分:2)
这假设节点x具有以下值:
您可能想要创建一个名为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”本身。
以下方法假定树是您问题中的示例的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;
}
但是,如果您希望它适用于任何二叉树,请不要使用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;
}
}
该方法应该像
一样调用tree.root = trim(tree.root, min, max);
答案 2 :(得分:0)
使用树时,我发现最简单的方法是使用Node
并返回Node
的递归方法,我的想法是我可以调用方法来“更新”我下面的节点通过调用它们的方法。
在这种情况下,例如,您可以使用Node minBound(Node)
返回此节点的子树,该子树位于下限之上。如果当前Node
在绑定中,则递归地应用于每个子节点并返回自己。如果当前Node
不在边界内,则以正确的方向返回更新的子Node
。如果当前Node
为null
,则只返回null
。
必须为maxBound
编写等效方法。
然后你可以minBound(maxBound(root))
来获取树的新根。
(您可以将minBound
和maxBound
合并到一个方法中,但为了便于解释,我决定将它们分开。)
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;
}