我正在开发一个BST,它将根据节点及其元素来平衡节点,其中点击是使用find(),contains()等找到节点时增加的属性。 树的根是具有最高命中数的节点。 我的所有代码都没有问题,除了在我增加命中后平衡树的平衡方法。 我正在使用修改后的AVL树旋转方法(),我不比较元素,而是比较节点的命中。 无论我尝试什么,我都无法让它工作,我无法让树正确平衡 到目前为止,这是我的代码:
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方法只是删除它应该旋转的节点,我尝试调试它但看不出有什么问题。
答案 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;
}
假设您在每次插入后重新平衡树,那么在旋转之后无需递归以平衡子树。
没有轮换,就需要递归。
当前算法向左和向右递归,但如果在左侧进行了轮换,则不再可以递归右子树。
这种修改算法更令人担忧的是它可能无法稳定:保持重新平衡。但是你肯定会发现测试。