低效二进制搜索树平衡算法

时间:2014-11-09 23:12:05

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

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

以下是我的代码片段:

@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;
    }
}

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

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

当你有这样的重叠问题可以通过较小的问题推断出来时,你的脑袋里必须响起一个响铃:动态编程。您可以计算BinaryTreeNode<Integer>,其中包含每个相应节点的深度(此树将具有与原始树相同的形状)。然后,您只需要遍历此树一次以执行计算,总时间复杂度为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)中访问其深度,因此同一父节点的子节点之间的深度比较将变得便宜!