【问题标题】:Inefficient Binary Search Tree Balanced Algorithm低效的二叉搜索树平衡算法
【发布时间】:2014-11-13 04:06:30
【问题描述】:

我正在开发一个使用二叉搜索树的项目。这个项目需要我创建一个名为 isBalanced 的方法来检查二叉搜索树是否在容差范围内平衡。我能够弄清楚如何做到这一点,但它非常缓慢。我想知道是否有人有任何技巧可以提高效率。顺便说一句,如果孩子为空,.getLeftChild() 和 .getRightChild() 必须返回 IllegalStateExceptions。我更希望他们亲自返回 null 。

这是我的代码的 sn-p:

@Override
public <T> int getDepth(BinaryTreeNode<T> root) {
    return recDepth(root,0);
}

public <T> int recDepth(BinaryTreeNode<T> root,int depth) {
    int leftTree,rightTree;
    if(!root.hasLeftChild()&&!root.hasRightChild()) return depth;

    if(!root.hasLeftChild()) leftTree = 0;
    else                     leftTree = recDepth(root.getLeftChild(),depth+1);

    if(!root.hasRightChild()) rightTree = 0;
    else                      rightTree = recDepth(root.getRightChild(),depth+1);

    if(rightTree>leftTree) return rightTree; 
    else                   return leftTree;
}

@Override
public <T> boolean isBalanced(BinaryTreeNode<T> root, int tolerance) {
    if(tolerance<0) throw new IllegalArgumentException("Can't have negative tolerance");
    if(root==null) throw new NullPointerException();
    return recBalanced(root,tolerance);
}

public <T> boolean recBalanced(BinaryTreeNode<T> root, int tolerance){
    try{
    if(Math.abs(getDepth(root.getLeftChild())-getDepth(root.getLeftChild()))<=tolerance){
        return recBalanced(root.getLeftChild(),tolerance)&&recBalanced(root.getRightChild(),tolerance);
    }else return false;
    } catch (IllegalStateException e){
        if(root.hasLeftChild()&&getDepth(root.getLeftChild())>tolerance-1) return false;
        else if(root.hasRightChild()&&getDepth(root.getRightChild())>tolerance-1) return false;
        else return true;
    }
}

提前感谢您的帮助。

【问题讨论】:

  • 我重新格式化了代码以使其更具可读性,但您可以使用条件运算符对其进行改进(我没有这样做,因为我不想使代码变性)
  • 对不起,可读性不是很好,感谢编辑。
  • 这就是为什么它是评论而不是答案。我已经确定了这段代码效率的原因,并试图向您提出修复建议。

标签: java binary-tree binary-search-tree


【解决方案1】:

您的效率问题来自这样一个事实,即您多次遍历相同的元素来计算子树的深度,然后计算其左右子树的深度。

当您遇到可以由较小问题推断出的重叠问题时,您的脑海中一定会响起警钟:动态规划。您可以计算一个BinaryTreeNode&lt;Integer&gt;,它将包含每个相应节点的深度(这棵树的形状与原始树的形状相同)。然后,您只需要遍历这棵树一次即可执行计算,总时间复杂度为 O(n)(但使用的内存为 O(n))。

public BinaryTreeNode<Integer> computeDepthTree(BinaryTreeNode<T> bt) {
    return computeDepth(bt,0);
}

public BinaryTreeNode<Integer> computeDepthTree(BinaryTreeNode<T> bt, int depth) {
    BinaryTreeNode<Integer> result = new BinaryTreeNode<>(depth);
    if (bt.getLeftNode() != null)
        result.setLeftNode(computeDepthTree(bt.getLeftNode(),depth + 1));

    if (bt.getRightNode() != null)
        result.setRightNode(computeDepthTree(bt.getRightNode(),depth + 1));

    return result;
}

通过计算这棵树,当遍历给定节点时,您将在O(1) 中访问它的深度,因此同一父节点的子节点之间的深度比较会很便宜!

【讨论】:

  • 如果我听起来完全没有经验,我很抱歉,但我不知道该怎么做。另外,您的意思是 O(1) 时间复杂度吗?
  • 不,它是O(n),因为所有节点都被遍历了一次或两次。
  • 我现在明白了,对不起,因为你这么说,我才弄糊涂了。你的解决方案很棒。非常感谢。
  • 你的方法与我想要的相反,但你的想法编码是微不足道的。
  • 好的,很高兴知道它对您有所帮助。不过,我不会反对善意的投票:)
猜你喜欢
  • 1970-01-01
  • 2013-12-18
  • 1970-01-01
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多