应用对数导航树

时间:2010-09-21 21:54:13

标签: algorithm math data-structures tree traversal

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

我不再记得如何运用这种技巧。任何人都可以重新介绍我吗?

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

5 个答案:

答案 0 :(得分:3)

既然你提到了要么向左还是向右,我会假设你正在特别谈论二叉树。在那种情况下,我认为你是对的。如果您的节点从左到右,从上到下编号,从1开始,那么您可以通过获取节点编号的log2来找到等级(树中的深度)。要从根再次查找该节点,可以使用数字的二进制表示,其中0 =左,1 =右。

例如:

  • n = 11

  • 二进制11是1011

  • 我们总是忽略第一个1,因为每个数字都会出现(所有n级节点都是n + 1位的二进制数,第一个数字是1)。我们留下的是011,这是从根本左边说,然后是右边,然后是右边。

如果要查找下一个有序叶子,请取当前叶子的数字并添加一个,然后使用此方法从根遍历。

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

答案 1 :(得分:2)

好的,此提案需要的字符多于我可以放入评论框的字符数。 Steven不相信知道树中节点的深度是有用的。我觉得是这样的。我过去一直都错了,我相信将来我会犯错,所以我会试着解释一下这个想法是如何起作用的,试图在当前没有错。如果我,我提前道歉。我几乎可以肯定,我使用CLR书从我的算法和数据结构课程中获得了它。请原谅或用法术说明任何单据,我暂时没有研究过这些东西。

引用wikipedia,“一个完整的二叉树是一个二叉树,其中除了可能是最后一个级别之外,每个级别都被完全填充,并且所有节点都尽可能地离开。

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

现在,如果给定位置值,我们可以按以下方式找到节点。获取我们正在寻找的元素的位置值的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)."

这很有用,因为你可以简单地遍历到这个级别,然后开始环顾四周。了解节点所在的深度非常有用也很重要,因此您可以开始查看,而不是开始查看开头。除非您知道所处的树的级别,否则您可以开始按顺序查看所有节点。

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

这有点奇怪,因为具有“位置值”不是我们通常在树中关心的东西。我可以看出为什么史蒂夫在数组方面想到了这一点,因为位置值是数组中固有的。

-Brian J. Stinar -

答案 2 :(得分:1)

至少类似于你的描述的东西是Binary Heap,使用了a.o.在优先级队列中。

答案 3 :(得分:1)

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

假设树节点已编号,从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。除了轶事之外,寻找节点的算法如下:

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

因此,例如,如果节点11是您所寻求的,那么您首先计算3.459的日志。然后...

  1. 3-459< =小于.5的分数:向左转并将整数减少到2。
  2. 2-918< =倍增分数大于.5:右转并将整数减少为1。
  3. 1-836< =倍增.918给出1.836:但只有小数部分计数:向右转,然后将整数除以前为0.完成!!
  4. 通过适当的住宿,相同的技术似乎适用于任何平衡的n-ary树。例如,给定一个平衡的三元树,跟随左,中或右边缘的选择再次基于对数的小数部分,如下所示:

    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
    

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

答案 4 :(得分:0)

案例1:节点指向其父级的指针

node开始,遍历parent指针,直到找到具有非空right_child的指针。只要它们非空,就转到right_child并遍历left_child

案例2:节点没有指向父

指针

root开始,找到node的路径(包括rootnode)。然后在路径中找到具有非空right_child的最新顶点(即节点)。只要它们是非空的,就转到right_child并遍历left_child

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