【问题标题】:Binary Search Tree balance二叉搜索树平衡
【发布时间】:2016-10-24 04:08:52
【问题描述】:

我正在开发一个 BST,它将根据节点的命中及其元素平衡节点,其中命中是一个属性,当使用 find()、contains() 等找到节点时会增加。 树的根是命中次数最多的节点。 我所有的代码都很好,除了在我增加命中后平衡树的平衡方法。 我正在使用修改后的 AVL 树旋转方法(https://users.cs.fiu.edu/~weiss/dsj2/code/weiss/nonstandard/Rotations.java),我不比较元素,而是比较节点的命中。 无论我尝试什么,我都无法让它工作,我无法让树正确平衡 到目前为止,这是我的代码:

 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 方法只是删除了它应该旋转的节点,我尝试调试它但看不出有什么问题。

【问题讨论】:

  • balanceTree 中对node 的分配没有完成任何事情。这可能与stackoverflow.com/questions/40480/… 重复。
  • 它应该旋转到哪一边?当它大于左或右时,它会旋转相邻节点,这不是一个无限循环吗?(例如平衡是什么,这到底是不是一个 List 实现,它是按 hitCount 排序的?[提示提示])
  • @ajb 在这种情况下提供的链接有什么帮助? OP 知道机制,但没有正确的分配。
  • @n247s 很难说 OP 是否知道......我看到很多问题,程序员认为分配给参数会对调用者传递的参数产生影响。此外,它符合这个问题:OP 说删除了一个节点,并且由于代码中没有删除,这似乎意味着该节点不再与任何父节点链接 - 如果他通过父节点可能会发生这种情况(root 这里)作为参数并期望它被改变。所以......也许,也许不是。
  • 没用。它应该围绕节点本身旋转,而不是相邻节点(它确实进入循环,我已经尝试过)。我尝试创建一个新的临时节点并将其设置为旋转方法返回的值,这确实旋转了节点,但不是以我期望的方式。它的逻辑有问题,但我看不到。

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


【解决方案1】:

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

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

没有旋转就需要递归。

当前算法先向左再向右递归,但如果在左侧发生旋转,则右子树可能不再递归。

这种修改算法更令人担忧的是它可能不稳定:保持再平衡。但你肯定会在测试中发现这一点。

【讨论】:

    【解决方案2】:

    这段代码有 2 个问题。
    1) 我错过了这棵树的结构。所以他们需要根据他们的 hitCount 进行排序,不是基本上是一个 List/Collection 在 hitCount 上排序的吗?

    现在,如果节点的 hitCount 比自己高,则您正在将节点与左右节点交换。所以想象 2 个节点 [A, B] A 有 1 个 hitCount,B 有 2 个 hitCounts。所以在排序时(你可能会遍历节点):
    开始情况:[A, B]

    第一类: A 的 hitCount 比 B 低,因此与右交换。结果 = [B, A]

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

    我们在哪里结束?一个更好的主意可能是使用列表并根据节点的命中数对节点进行排序。这样你就不必搞砸这一切了。

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

    当然,“rotateWithRightChild”正好相反。

    我希望这对你有所帮助。

    编辑:

    如何实现订单列表/集合? 将节点添加到树后,只需将节点添加到 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

    【讨论】:

    • 我明白你对列表的意思,只是我没有知识或时间使用列表重做它。至于您对方法的更正,不幸的是,它仍然循环。
    • 我编辑了我的答案以显示一个简单的 List 实现。我相信它的方式比你现在的方式更省时。其次,我更正了 Swap 方法,但如果你仔细阅读,我在第一节中解释了为什么它会永远循环。 (ps.问题出在balanceTree()方法上)
    猜你喜欢
    • 1970-01-01
    • 2013-12-18
    • 2012-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    相关资源
    最近更新 更多