[英]Javascript: Binary Search Tree in order traversal recursive confusion
given the code below, I am bit confused as to how the order of operations happens to get an in order traversal of a binary search tree.鉴于下面的代码,我对操作顺序如何碰巧获得二叉搜索树的顺序遍历感到有些困惑。
BinarySearchTree.prototype.inOrder = function() {
if (this.root == null) {
return null;
} else {
var result = new Array();
function traverseInOrder(node) {
node.left && traverseInOrder(node.left);
result.push(node.data);
node.right && traverseInOrder(node.right);
}
traverseInOrder(this.root);
return result;
};
}
I tried to add a debugger statement and follow but I get lost inside:我试图添加一个调试器语句并遵循,但我迷失在里面:
function traverseInOrder(node) {
node.left && traverseInOrder(node.left); //step 1
result.push(node.data); //step 2
node.right && traverseInOrder(node.right); //step 3
}
node.left && traverseInOrder(node.left);
(Step 1) gets run then gets run again then gets run again. (步骤 1)运行,然后再次运行,然后再次运行。 Finally when there is no
node.left
, Step 2 gets called: result.push(node.data);
最后,当没有
node.left
时,调用第 2 步: result.push(node.data);
This is the part where it loses me .这是它失去我的部分。 Now it tries to run
node.right && traverseInOrder(node.right)
but there is no node.right
but instead of moving out of the function, it goes back up to Step 2, result.push(node.data);
现在它尝试运行
node.right && traverseInOrder(node.right)
但没有node.right
而是没有移出 function,而是返回到步骤 2, result.push(node.data);
. .
Is this queued up from the multiple recursive calls in Step 1?这是从步骤 1 中的多个递归调用中排队的吗?
Let's look at an example.让我们看一个例子。 Let it be the below tree which will be traversed
in order
.让它成为将按
in order
遍历的下面的树。
traverseInOrder
is called with this.root
, it means the parameter from the above example is A
.traverseInOrder
是用this.root
调用的,这意味着上例中的参数是A
。 The node.left
exists, it follows traverseInOrder
is called with parameter B
. node.left
存在,它遵循traverseInOrder
调用参数B
。
B
the node.left
exists, it follows traverseInOrder
is called with parameter D
.B
的调用中node.left
存在,它遵循traverseInOrder
被调用参数D
。
D
node.left
does not exist ( node.left
is falsy), so result.push(node.data);
D
的调用中node.left
不存在( node.left
是假的),所以result.push(node.data);
is called with parameter D
.D
调用。 In the next step node.right
is falsy, it follows the traversInOrder
with parameter D
is finished.node.right
是假的,它遵循带有参数D
的traversInOrder
完成。 We get back to the B
.B
。B
, and because the traversInOrder
with D
just finished, result.push(node.data)
will be called with parameter B
.B
,因为带有D
的traversInOrder
刚刚完成, result.push(node.data)
将使用参数B
调用。 And as next node.right
is truthy so traverseInOrder
is called with the node.right
so with E
.node.right
是真实的,因此使用node.right
调用traverseInOrder
,因此使用E
调用。
E
node.left
is falsy, result.push
is called with parameter E
.E
node.left
是假的, result.push
使用参数E
调用。 node.right
is falsy is the call with E
ended here. node.right
是 falsy 是与E
的通话在这里结束。 We get back to call A
, because as we return from here to the call of B
it finishes at this point.A
,因为当我们从这里返回到调用B
时,它在这一点上完成。A
we just finished the left node, result.push(node.data);
A
调用时,我们刚刚完成了左侧节点result.push(node.data);
is called for A
and next node.right
is truthy so result.push(node.data)
is called with the right node witch means parameter C
.A
调用并且下一个node.right
是真实的,因此使用右节点调用result.push(node.data)
意味着参数C
。 And it goes on the same with the C,F,G. C,F,G 也是如此。
tenkmilan already did an excellent job of showing how to envision that code. tenkmilan 已经出色地展示了如何构想该代码。
Here I go a different path, and write a simpler inorder
traversal.这里我go路径不同,写一个更简单的中
inorder
遍历。 It should be fairly clear how that can map to the code supplied.应该很清楚 map 提供的代码如何。
An inorder
traversal is simple enough.中
inorder
遍历很简单。 preorder
and postorder
are the other most common tree traversals and they work on arbitrary finite trees. preorder
和postorder
是其他最常见的树遍历,它们适用于任意有限树。 Inorder is only defined for binary trees, and uses the left
- and right
-children of your node. right
left
节点。 The traversal order is to (recursively) traverse the left child, then visit the node itself, and finally to (recursively) traverse the right child.遍历顺序是(递归)遍历左孩子,然后访问节点本身,最后(递归)遍历右孩子。
We can write such a traversal simply:我们可以简单地编写这样的遍历:
const inorder = (tree) =>
tree
? [
... inorder (tree .left),
tree .data,
... inorder (tree .right)
]
: []
We have a base-case where the node we're looking at is empty, and we just return an empty array.我们有一个基本情况,我们正在查看的节点是空的,我们只返回一个空数组。 In the general case we just concatenate together a recursive call on
left.tree
with our current node's value and a recursive call on right.tree
.在一般情况下,我们只是将
left.tree
上的递归调用与当前节点的值和right.tree
上的递归调用连接在一起。
That's all there is to inorder
traversal.这就是中
inorder
遍历的全部内容。 You can see it in action in this snippet:您可以在此代码段中看到它的实际效果:
const inorder = (tree) => tree? [... inorder (tree.left), tree.data, ... inorder (tree.right) ]: [] const tree = { data: 'F', left: { data: 'B', left: {data: 'A'}, right: { data: 'D', left: {data: 'C'}, right: {data: 'E'} } }, right: { data: 'H', left: {data: 'G'}, right: {data: 'I'} } } console.log (inorder (tree))
Of course, this is for a simple tree stored as a plain JS object.当然,这是针对存储为普通 JS object 的简单树。 But mapping back your sample code is easy enough.
但是映射回您的示例代码很容易。 I'm guessing that if you can follow this one, you can quickly follow that one.
我猜如果你能关注这个,你就可以快速关注那个。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.