应用对数来导航树

发布于 2024-09-24 09:04:06 字数 216 浏览 1 评论 0原文

我曾经知道一种使用对数从树的一片叶子移动到树的下一个“有序”叶子的方法。我认为它涉及获取“当前”叶子的位置值(排名?)并将其用作从根向下到新目标叶子的新遍历的种子 - 一直使用对数函数测试来确定是否沿着右或左节点向下到达叶子。

我已经不记得如何运用这项技术了。有谁可以重新介绍一下我吗?

我也不记得该技术是否要求树是平衡的,或者它是否适用于 n 树或仅适用于二叉树。任何信息将不胜感激。

I had once known of a way to use logarithms to move from one leaf of a tree to the next "in-order" leaf of a tree. I think it involved taking a position value (rank?) of the "current" leaf and using it as a seed for a fresh traversal from the root down to the new target leaf - all the way using a log function test to determine whether to follow the right or left node down to the leaf.

I no longer recall how to exercise that technique. Can anyone re-introduce me?

I also don't recall if the technique required the tree to be balanced, or if it worked on n-trees or only binary trees. Any info would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

风吹过旳痕迹 2024-10-01 09:04:06

既然您提到了向左还是向右,我假设您正在专门讨论二叉树。在这种情况下,我认为你是对的,有办法。如果您的节点从左到右、从上到下编号,从 1 开始,那么您可以通过取节点编号的 log2 来找到排名(树中的深度)。要从根再次找到该节点,可以使用数字的二进制表示形式,其中 0 = 左,1 = 右。

例如:

  • n = 11

  • 二进制中的 11 是 1011

  • 我们总是忽略第一个 1,因为它每次都会出现number(第n级的所有节点都是n+1位的二进制数,第一位为1)。我们剩下 011,这意味着从根开始向左,然后向右,然后向右。

如果要找到下一个有序叶子,请获取当前叶子的编号并加一,然后使用此方法从根开始遍历。

我相信这只适用于平衡二叉树。

Since you mentioned whether to go left or right, I'm going to assume you're talking about a binary tree specifically. In that case, I think you're right that there is a way. If your nodes are numbered left-to-right, top-to-bottom, starting with 1, then you can find the rank (depth in the tree) by taking the log2 of the node's number. To find that node again from the root, you can use the binary representation of the number, where 0 = left and 1 = right.

For example:

  • n = 11

  • 11 in binary is 1011

  • We always ignore the first 1 since it's going to be there for every number (all nodes of rank n will be binary numbers with n+1 digits, with the first digit being 1). We're left with 011, which is saying from the root go left, then right, then right.

If you want to find the next in-order leaf, take the current leaf's number and add one, then traverse from the root using this method.

I believe this only works with balanced binary trees.

猫弦 2024-10-01 09:04:06

好的,这个提案需要的字符数超出了我在评论框中所能容纳的字符数。 Steven 不认为了解树中节点的深度是有用的。我认为是的。我过去错了,而且我确信我将来也会错,所以我将尝试解释这个想法是如何运作的,试图在现在不犯错。如果是的话,我会提前道歉。我几乎可以肯定我是从我的一门算法和数据结构课程中使用 CLR 书获得的。请原谅任何符号或术语的错误,我已经有一段时间没有研究这些东西了。

引用维基百科,“完全二叉树是一个二叉树,其中每个级别,除了可能的最后一个,都被完全填满,并且所有节点都尽可能远离左侧。”

我们正在考虑具有任意分支度的完整树(其中二叉树的分支度为二)。此外,我们正在考虑我们的节点有一个“位置值”,它是节点位置值的排序(从上到下,从左到右)。

现在,如果给定一个位置值,我们可以通过以下方式找到节点。取我们正在寻找的元素的位置值的log_base_n(这个元素的下限,我们想要一个整数)。从根向下遍历那么多次,减一。现在,开始查看该级别节点的所有子节点。您正在搜索的节点将在此集合中。

这是解释维基百科定义的附加部分的尝试:

"This depth is equal to the integer part of log2(n) where n 
 is the number of nodes on  the balanced tree. 

 Example 1: balanced tree with 1 node, log2(1) = 0 (depth = 0). 

 Example 2: balanced tree with 3 nodes, log2(3) = 1.59 (depth=1). 

 Example 3: balanced tree with 5 nodes, log2(5) = 2.32 
 (depth of tree is 2 nodes)."

这很有用,因为您可以简单地遍历到此级别,然后开始环顾四周。了解节点所在的深度非常有用且重要,因此您可以从那里开始查找,而不是从头开始查找。除非您知道自己位于树的哪一层,否则您将开始按顺序查看所有节点。

这就是为什么我认为了解我们正在搜索的节点的深度是有帮助的。

这有点奇怪,因为我们通常不关心树中的“位置值”。我可以理解为什么 Steve 会从数组的角度来考虑这个问题,因为位置值是数组所固有的。

-布莱恩·J·斯蒂纳尔-

OK, this proposal requires more characters than I can fit into a comment box. Steven does not believe that knowing the depth of the node in the tree is useful. I think it is. I have been wrong in the past, and I'm sure I'll be wrong in the future, so I will try to explain how this idea works in an attempt to not be wrong in the present. If I am, I apologize ahead of time. I'm nearly certain I got it from one of my Algorithms and Datastructures courses, using the CLR book. Please excuse any slips in notation or nomenclature, I haven't studied this stuff in a while.

Quoting wikipedia, "a complete binary tree is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible."

We are considering a complete tree with any branching degree (where a binary tree has a branching degree of two). Also, we are considering our nodes to have a 'positional value' which is an ordering of the positional value (top to bottom, left to right) of the node.

Now, if we are given a positional value, we can find the node in the following fashion. Take the log_base_n of the positional value of the element we are looking for (floor of this, we want an integer). Traverse down from the root that many times, minus one. Now, start looking through all the children of the nodes at this level. Your node you are searching for will be in this set.

This is an attempt in explaining the additional part of the wikipedia definition:

"This depth is equal to the integer part of log2(n) where n 
 is the number of nodes on  the balanced tree. 

 Example 1: balanced tree with 1 node, log2(1) = 0 (depth = 0). 

 Example 2: balanced tree with 3 nodes, log2(3) = 1.59 (depth=1). 

 Example 3: balanced tree with 5 nodes, log2(5) = 2.32 
 (depth of tree is 2 nodes)."

This is useful, because you can simply traverse down to this level and then start looking around. It is useful and important to know the depth your node is located on, so you can start looking there, instead of starting to look at the beginning. Unless you know what level of the tree you are on, you get to start looking at all the nodes sequentially.

That is why I think it is helpful to know the depth of the node we are searching for.

It is a little bit odd, since having the "positional value" is not something we normally care about in a tree. I can see why Steve thought of this in terms of an array, since positional value is inherent in arrays.

-Brian J. Stinar-

一世旳自豪 2024-10-01 09:04:06

至少类似于您的描述的是 二进制堆,在优先级队列中使用 ao 。

Something that at least resembles your description is the Binary Heap, used a.o. in Priority Queues.

逆光下的微笑 2024-10-01 09:04:06

我想我已经找到了答案,或者至少是一份传真。

假设树节点已编号,从 1 开始,从上到下、从左到右。假设遍历从根开始,并在找到节点 X 时停止(这意味着父节点链接到其子节点)。另外,为了快速参考,节点 1 到 12 的以 2 为底的对数值为:

log2(1) = 0.0
log2(2) = 1
log2(3) = 1.58
log2(4) = 2
log2(5) = 2.32     
log2(6) = 2.58     
log2(7) = 2.807
log2(8) = 3
log2(9) = 3.16
log2(10) = 3.32
log2(11) = 3.459
log2(12) = 3.58

小数部分表示唯一的对角位置(注意节点 3、6 和 12 的小数部分都是 0.58)。另请注意,每个节点属于树的左侧或右侧,具体取决于对数小数部分是否小于或大于 0.5。抛开轶事不谈,查找节点的算法如下:

  • 检查小数部分,如果小于 0.5,则向左转。否则右转。
  • 从日志的整数部分减一,如果值达到零则停止。
  • 将小数部分加倍,然后重新开始。

因此,举例来说,如果节点 11 是您要查找的节点,那么您首先计算对数 3.459。然后...

  1. 3-459 <= 小于 0.5 的分数:左转并将整数减至 2。
  2. 2-918 <= 大于 0.5 的双倍分数:右转并将整数减至 1。
  3. 1-836 <=加倍 0.918 得到 1.836:但只有小数部分计数:右转并将先前的整数除以 0。完成!

通过适当的调整,相同的技术似乎适用于任何平衡的 n 叉树。例如,给定平衡三叉树,以下左、中或右边缘的选择再次基于日志的小数部分,如下所示:

between 0.5-0.832: turn left  (a one-third fraction range)
between 0.17-0.49: turn right  (another one-third fraction range)
otherwise go down the middle.  (the last one-third range)

通过将小数部分乘以 3 而不是 2 来调整算法。 ,对于那些想要测试最后一个陈述的人来说,这是一个快速参考:

log3(1) = 0.0
log3(2) = 0.63          
log3(3) = 1             
log3(4) = 1.26          
log3(5) = 1.46
log3(6) = 1.63
log3(7) = 1.77
log3(8) = 1.89          
log3(9) = 2

此时我想知道是否有一种更简洁的方法来表达整个“基于日志的自上而下的节点选择”。我很感兴趣,如果有人知道的话...

I think I've found the answer, or at least a facsimile.

Assume the tree nodes are numbered, starting at 1, top-down and left-to-right. Assume traversal begins at the root, and halts when it finds node X (which means the parent is linked to its children). Also, for quick reference, the base 2 logarithmic values for nodes 1 through 12 are:

log2(1) = 0.0
log2(2) = 1
log2(3) = 1.58
log2(4) = 2
log2(5) = 2.32     
log2(6) = 2.58     
log2(7) = 2.807
log2(8) = 3
log2(9) = 3.16
log2(10) = 3.32
log2(11) = 3.459
log2(12) = 3.58

The fractional portion represents a unique diagonal position (notice how nodes 3, 6, and 12 all have fractional portion 0.58). Also notice that every node belongs either to the left or right side of the tree, depending on whether the log fractional component is less or great than 0.5. Anecdotes aside, the algorithm for finding a node is then as follows:

  • examine fractional portion, if it is less than .5, turn left. Else turn right.
  • subtract one from the whole number portion of the log, stop if the value reaches zero.
  • double the fractional portion, and start over.

So, for example, if node 11 is what you seek then you start by computing the log which is 3.459. Then...

  1. 3-459 <=fraction less than .5: turn left and decrement whole number to 2.
  2. 2-918 <=doubled fraction more than .5: turn right and decrement whole number to 1.
  3. 1-836 <=doubling .918 gives 1.836: but only fractional part counts: turn right and dec prior whole number to 0. Done!!

With appropriate accomodations, the same technique appears to work for any balanced n-ary tree. For example, given a balanced ternary tree, the choice of following left, middle, or right edges is again based on the fractional portion of the log, as follows:

between 0.5-0.832: turn left  (a one-third fraction range)
between 0.17-0.49: turn right  (another one-third fraction range)
otherwise go down the middle.  (the last one-third range)

The algorithm is adjusted by multiplying the fractional portion by 3 instead of 2. Again, a quick reference for those who want to test this last statement:

log3(1) = 0.0
log3(2) = 0.63          
log3(3) = 1             
log3(4) = 1.26          
log3(5) = 1.46
log3(6) = 1.63
log3(7) = 1.77
log3(8) = 1.89          
log3(9) = 2

At this point I wonder if there is an even more concise way to express this whole "log-based top-down selection of a node." I'm interested if anyone knows...

叹梦 2024-10-01 09:04:06

情况 1:节点指向其父节点的指针

节点开始,向上遍历parent指针,直到具有非空right_child的节点找到了。转到right_child并遍历left_child,只要它们不为空。

情况 2:节点没有指向父节点的指针

开始,查找到节点的路径(包括节点)。然后找到路径中具有非空right_child的最新顶点(即节点)。转到 right_child 并遍历 left_child,只要它们不为 null。

在这两种情况下,我们都会从根向上或向下遍历到其中一个节点。这种遍历的最大值是树的深度的顺序,因此如果树是平衡的,则节点的大小是对数的。

Case 1: Nodes have pointers to their parent

Starting from the node, traverse up the parent pointer until one with non-null right_child is found. Go to the right_child and traverse left_child as long as they are non-null.

Case 2: Nodes do not have pointers to the parent

Starting from the root, find the path to the node (including the root and the node). Then find the latest vertex (i.e. a node) in the path that has non-null right_child. Go the the right_child and traverse left_child as long as they are non-null.

In both cases, we traversing either up or down from the root to one of the nodes. The maximum of such traversal is in the order of the depth of the tree, hence logarithmic in the size of the nodes if the tree is balanced.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文