二进制搜索树平衡

时间:2016-10-23 18:49:49

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

我正在开发一个BST,它将根据节点及其元素来平衡节点,其中点击是使用find(),contains()等找到节点时增加的属性。 树的根是具有最高命中数的节点。 我的所有代码都没有问题,除了在我增加命中后平衡树的平衡方法。 我正在使用修改后的AVL树旋转方法(enter image description here),我不比较元素,而是比较节点的命中。 无论我尝试什么,我都无法让它工作,我无法让树正确平衡 到目前为止,这是我的代码:

 public void balanceTree() {
    balanceTree(root);
}

private void balanceTree(Node node) {

    if (node.left.getHits() <= node.getHits() && node.right.getHits() <= node.getHits()) {
        return;
    } else if (node.left.getHits() > node.getHits()) {
        node = rotateWithLeftChild(node);

    } else if (node.right.getHits() > node.getHits()) {
        node = rotateWithRightChild(node);

    }


}

static Node rotateWithLeftChild(Node k2) {
    Node k1 = k2.left;
    k2.left = k1.right;
    k1.right = k2;
    return k1;
}

static Node rotateWithRightChild(Node k1) {
    Node k2 = k1.right;
    k1.right = k2.left;
    k2.left = k1;
    return k2;
}

现在,balance方法只是删除它应该旋转的节点,我尝试调试它但看不出有什么问题。

2 个答案:

答案 0 :(得分:0)

此代码有两个问题。
1)我想念这棵树的结构。所以他们需要根据他们的hitCount进行排序,基本上是基于hitCount排序的List / Collection?

现在你正在用他们的左右节点交换节点,如果他们有比自己更高的hitCount。所以想象2个节点[A,B] A有1个hitCount而B有2个hitCounts。所以在排序时(你可以在节点上进行迭代):
  开始情况:[A,B]

首先排序:   A的hitCount低于B,因此与右侧交换。结果= [B,A]

第二种:   A的hitCount低于B,因此与左侧交换。结果= [A,B]

我们在哪里结束?更好的想法可能是使用List并根据其hitCount对节点进行排序。这样你就不必搞砸了这一切。

2)您的交换方法不像您认为的那样有效。仔细看看:

 static Node rotateWithLeftChild(Node k2) {
     Node k1 = k2.left;
     k2.left = k1.right;
     k1.right = k2;
     return k1;
 }

 // exact the same results:
 static Node rotateWithLeftChild(Node k2)
 {
     k2.left = k2;
     return k2.left;
 }

对我来说似乎不对。可能你的意思是:

 static Node rotateWithLeftChild(Node k2)
 {
     Node k1 = k2.left;
     k1.right = k2.right;
     k2.left = k1.left;
     k1.left = k2;
     k2.right = k1;
     return k1;
 }

当然,反之亦然&#34; rotateWithRightChild&#34;。

我希望这对你有所帮助。

修改

如何为订单实施列表/集合? 将节点添加到树后,只需将节点添加到Lisf / Collection即可。当你想对节点进行排序时,只需使用它:

 //myNodesCollection is the List/Collection containing all the nodes.
 static void sortByHitCount()
 {
     Collections.sort(myNodesCollection, (n1, n2) -> n1.getHits() - n2.getHits());
 }

这可能看起来很复杂,但这是一种为您完成所有排序的方法。第一个参数是要排序的列表/集合。第二个参数是比较器,在这种情况下,比较每个节点的hitCount。

文档:https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

答案 1 :(得分:0)

在java中,无法更改传递的参数,因此需要返回新的Node值。

public void balanceTree() {
    root = balanceTree(root);
}

private Node balanceTree(Node node) 
    if (node.left.getHits() <= node.getHits()
            && node.right.getHits() <= node.getHits()) {
        node.left = balanceTree(node.left);
        node.right = balanceTree(node.right);
    } else if (node.left.getHits() > node.getHits()) {
        node = rotateWithLeftChild(node);
    } else if (node.right.getHits() > node.getHits()) {
        node = rotateWithRightChild(node);
    }
    return node;
}

假设您在每次插入后重新平衡树,那么在旋转之后无需递归以平衡子树。

没有轮换,就需要递归。

当前算法向左和向右递归,但如果在左侧进行了轮换,则不再可以递归右子树。

这种修改算法更令人担忧的是它可能无法稳定:保持重新平衡。但是你肯定会发现测试。