当不平衡时,二进制的AVL旋转
我正在尝试构建 avl tree ,但找不到很多代码例子,仅是理论。
我的代码具有所有旋转的实现,但是当树是1面时,我损失了一半的树。
这是我的代码:
function buildTree(dataSet) {
let root = null
function rotateRight(node) {
return rotate(node, true)
}
function rotateLeft(node) {
return rotate(node, false)
}
function rotate(node, right) {
const inputNodeSide = right ? "left" : "right"
const targetNodeSide = right ? "right" : "left"
const targetNode = node[inputNodeSide]
const targetNodeChild = targetNode[targetNodeSide]
targetNode[targetNodeSide] = node
node[inputNodeSide] = targetNodeChild
return targetNode // as this is at the top
}
function createNode(data) {
return {
data,
left: null,
right: null,
get balance() {
return workOutHeight(this.left) -
workOutHeight(this.right)
},
get height() {
return workOutHeight(this)
},
}
} // END createNode
function workOutHeight(node) {
if (null === node) {
return -1
}
return Math.max(workOutHeight(node.left),
workOutHeight(node.right)) + 1
}
function avl(node) {
const balanced = node.balance
if (2 === balanced) {
if (0 > node.left.balance) {
node.left = rotateLeft(node.left);
}
return rotateRight(node);
} else if (-2 === balanced) {
if (0 < node.right.balance) {
node.right = rotateRight(node.right);
}
return rotateLeft(node);
}
return node
}
this.add = function(data, parent) {
parent = parent || root;
if (null === parent) {
return root = createNode(data);
} else if (data < parent.data) {
if (null === parent.left) {
return parent.left = createNode(data);
}
this.add(data, parent.left)
avl(parent)
} else if (data > parent.data) {
if (null === parent.right) {
return parent.right = createNode(data);
}
this.add(data, parent.right)
avl(parent)
}
} // END addData
this.tree = function() {
return JSON.parse(JSON.stringify(root))
}
if (Array.isArray(dataSet)) {
dataSet.forEach(val => this.add(val))
}
} // END buildTree
console.log(new buildTree([2, 6, 9, 4, 7, 0]).tree())
正如您在运行片段时看到的那样,生成的树只有2个节点,而应该有6个节点。我在哪里出错了?
I'm trying to build an AVL tree, but was not able to find a lot of code examples, only theory.
My code has the implementation for all rotations, but when the tree is 1 sided, I lose half the tree.
Here is my code:
function buildTree(dataSet) {
let root = null
function rotateRight(node) {
return rotate(node, true)
}
function rotateLeft(node) {
return rotate(node, false)
}
function rotate(node, right) {
const inputNodeSide = right ? "left" : "right"
const targetNodeSide = right ? "right" : "left"
const targetNode = node[inputNodeSide]
const targetNodeChild = targetNode[targetNodeSide]
targetNode[targetNodeSide] = node
node[inputNodeSide] = targetNodeChild
return targetNode // as this is at the top
}
function createNode(data) {
return {
data,
left: null,
right: null,
get balance() {
return workOutHeight(this.left) -
workOutHeight(this.right)
},
get height() {
return workOutHeight(this)
},
}
} // END createNode
function workOutHeight(node) {
if (null === node) {
return -1
}
return Math.max(workOutHeight(node.left),
workOutHeight(node.right)) + 1
}
function avl(node) {
const balanced = node.balance
if (2 === balanced) {
if (0 > node.left.balance) {
node.left = rotateLeft(node.left);
}
return rotateRight(node);
} else if (-2 === balanced) {
if (0 < node.right.balance) {
node.right = rotateRight(node.right);
}
return rotateLeft(node);
}
return node
}
this.add = function(data, parent) {
parent = parent || root;
if (null === parent) {
return root = createNode(data);
} else if (data < parent.data) {
if (null === parent.left) {
return parent.left = createNode(data);
}
this.add(data, parent.left)
avl(parent)
} else if (data > parent.data) {
if (null === parent.right) {
return parent.right = createNode(data);
}
this.add(data, parent.right)
avl(parent)
}
} // END addData
this.tree = function() {
return JSON.parse(JSON.stringify(root))
}
if (Array.isArray(dataSet)) {
dataSet.forEach(val => this.add(val))
}
} // END buildTree
console.log(new buildTree([2, 6, 9, 4, 7, 0]).tree())
As you can see when running the snippet, the resulting tree only has 2 nodes, while there should be 6. Where did I go wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于
this.add
方法。它调用
avl
忽略该调用返回的节点。该返回的节点应替换作为参数传递的节点。由于您不知道该返回的节点应附加到哪儿处理此“返回”功能的功能。这是可以改编的方法:
请注意,我在此处将分配删除到
root
。我建议将其移至您将初始调用到this.add
的地方:现在它将起作用。
重新设计
为JavaScript自2015年以来的JavaScript已成为
类
语法,我实际上会使用它,并创建tree> tree
和node
class。可以使用#
语法创建私有成员。同样,计算节点的每时每刻都需要计算节点的平衡因子的高度。 AVL树的好处是,当您知道要旋转的节点的平衡因素时,您可以从它们的新平衡因素中得出 - 而无需实际高度。
这是所有这些都放在代码中,并附加一个输入框,您可以将节点添加到树上。该树以简单的凹痕格式显示(左侧的根)。
The problem is in the
this.add
method.It calls
avl
ignoring the node that is returned by that call. This returned node should replace the node that was passed as argument. As you don't know where this returned node should be attached to, you should return it as the return value forthis.add
, and that means you should redesign that whole function to deal with this "return" feature.Here is how it could be adapted:
Note that I removed the assignment to
root
here. I would suggest to move that to the place where you make the initial call tothis.add
:And now it will work.
Redesign
As JavaScript has since ECMAScript 2015 the
class
syntax, I would actually make use of that, and create aTree
andNode
class. Private members can be created with the#
syntax.Also, it is not efficient to calculate the height of a node every moment you need to calculate the balance factor of a node. The nice thing of AVL trees is that when you know the balance factors of the nodes that are being rotated, you can derive from that their new balance factors -- without needing the actual heights.
Here is all of that put in code, with in addition an input box, with which you can add nodes to the tree. The tree is displayed with simple indentation format (with the root at the left side).