Algorithm 无限完整二叉树中两个节点之间的最短路径?

Algorithm 无限完整二叉树中两个节点之间的最短路径?,algorithm,binary-tree,shortest-path,Algorithm,Binary Tree,Shortest Path,假设我们有一个无限完整的二叉树,其中节点编号为1,2,3。。。按其位置逐层遍历树。给定树中两个节点u和v的索引,如何有效地找到它们之间的最短路径 谢谢 @Jonathan Landrum在评论中指出了解决方案。这个答案充实了这个解决方案 在任何树中,任意两个节点之间只有一条路径。因此,这个问题归结为确定这两个节点之间的唯一路径 在任何有根树中,两个节点u和v之间的最短路径可以通过查找两个节点的最低公共祖先x,然后连接从u到x和从x到v的路径来找到。因此,在您的情况下,您需要找到两个节点的LCA,

假设我们有一个无限完整的二叉树,其中节点编号为1,2,3。。。按其位置逐层遍历树。给定树中两个节点u和v的索引,如何有效地找到它们之间的最短路径


谢谢

@Jonathan Landrum在评论中指出了解决方案。这个答案充实了这个解决方案

在任何树中,任意两个节点之间只有一条路径。因此,这个问题归结为确定这两个节点之间的唯一路径

在任何有根树中,两个节点u和v之间的最短路径可以通过查找两个节点的最低公共祖先x,然后连接从u到x和从x到v的路径来找到。因此,在您的情况下,您需要找到两个节点的LCA,然后将这些路径粘合在一起

由于您有一个无限二叉树,我假设表示如下:

             1
       /             \
      2               3
    /   \           /   \
   4     5         6     7
  / \   / \       / \   / \
 8  9  10 11     12 13 14 15
如果将所有数字写成二进制,则此树形状具有一个非常有趣的特性:

                  1
            /         \
        10                  11
    /         \         /         \
  100        101       110       111
 /   \      /    \    /   \     /   \
1000 1001 1010 1011 1100 1101 1110 1111
有几件事你可以注意到。首先,每个节点的深度由1减去MSB的索引给出

接下来,请注意,如果一个数字有二进制表示b1 b2。。。bn-10亿,那么它的母公司是b1-b2。。。bn-1,如果bn=0,则为左子级,如果bn=1,则为右子级。通过反复应用这个属性,我们得到如下结果:当且仅当v>>k=u时,节点u是v的第k个祖先

这让我们有很多工作要做。通常,您可以通过以下方式计算LCAu,v:

如果u比v深,则从u向上移动直到到达与v相同深度的节点,反之亦然,如果v深,则从v向上移动。 以相同的速率从u和v向上走,直到它们到达相同的节点。该节点是LCA。 我们可以按如下方式直接在time-Olog-max{u,v}中实现这一点。要执行步骤1,请计算u和v的MSB索引,以确定每个节点的深度du和dv。让我们假设WLOG是dv≥ 杜。在这种情况下,通过计算v>>du-dv,我们可以找到在时间O1上与v深度相同的u的祖先。漂亮!在第二步中,我们比较u和v,如果它们不相等,将每一个向左移动一个点,模拟向上移动一级。我们可以执行此操作的最大次数由Olog max{u,v}给出,因此整个运行时是Olog max{u,v}

然而,我们可以通过使用改进的二进制搜索以指数方式加快速度。u和v的LCA深度必须介于0和min{du,dv}之间。一旦我们找到u和v的共同祖先x,我们就知道x的所有祖先也是u和v的共同祖先。因此,我们可以在LCA的可能深度上对u和v进行二进制搜索,通过使用位移位从该深度计算每个节点的祖先。这将在时间Olog log max{u,v}中运行,因为u的最大深度是Olog u,v的最大深度是Olog v

一旦我们找到了祖先,我们可以计算u和v之间的路径,如下所示。计算从u到该祖先的路径,方法是反复从u移开一位,直到我们到达共同的祖先。用同样的方法计算从v到祖先的路径,然后将该路径与第一步中找到的路径反向。此路径的长度由O | log u-log v |给出,因此运行时为O | log u-log v |

另一方面,如果你只需要路径的长度,你可以把从u到LCAu,v和从LCAu,v到v的距离相加。我们可以在每个Olog log max{u,v}时间中计算这些值,因此运行时是Olog log max{u,v}


希望这有帮助

@Jonathan Landrum在评论中指出了解决方案。这个答案充实了这个解决方案

在任何树中,任意两个节点之间只有一条路径。因此,这个问题归结为确定这两个节点之间的唯一路径

在任何有根树中,两个节点u和v之间的最短路径可以通过查找两个节点的最低公共祖先x,然后连接从u到x和从x到v的路径来找到。因此,在您的情况下,您需要找到两个节点的LCA,然后将这些路径粘合在一起

由于您有一个无限二叉树,我假设表示如下:

             1
       /             \
      2               3
    /   \           /   \
   4     5         6     7
  / \   / \       / \   / \
 8  9  10 11     12 13 14 15
如果将所有数字写成二进制,则此树形状具有一个非常有趣的特性:

                  1
            /         \
        10                  11
    /         \         /         \
  100        101       110       111
 /   \      /    \    /   \     /   \
1000 1001 1010 1011 1100 1101 1110 1111
有几件事你可以注意到。首先,每个节点的深度由1减去MSB的索引给出

接下来,请注意,如果一个数字有二进制表示b1 b2。。。bn-10亿,那么它的母公司是b1-b2。。。bn-1,如果bn=0,则为左子级,如果bn=1,则为右子级。通过反复应用这个属性,我们得到如下结果:当且仅当v>>k=u时,节点u是v的第k个祖先

这让我们有很多工作要做。通常,您可以通过以下方式计算LCAu,v:

如果u比v深,则从u向上移动,直到到达sa处的节点 将深度视为v,反之亦然,如果v更深,则从v向上移动。 以相同的速率从u和v向上走,直到它们到达相同的节点。该节点是LCA。 我们可以按如下方式直接在time-Olog-max{u,v}中实现这一点。要执行步骤1,请计算u和v的MSB索引,以确定每个节点的深度du和dv。让我们假设WLOG是dv≥ 杜。在这种情况下,通过计算v>>du-dv,我们可以找到在时间O1上与v深度相同的u的祖先。漂亮!在第二步中,我们比较u和v,如果它们不相等,将每一个向左移动一个点,模拟向上移动一级。我们可以执行此操作的最大次数由Olog max{u,v}给出,因此整个运行时是Olog max{u,v}

然而,我们可以通过使用改进的二进制搜索以指数方式加快速度。u和v的LCA深度必须介于0和min{du,dv}之间。一旦我们找到u和v的共同祖先x,我们就知道x的所有祖先也是u和v的共同祖先。因此,我们可以在LCA的可能深度上对u和v进行二进制搜索,通过使用位移位从该深度计算每个节点的祖先。这将在时间Olog log max{u,v}中运行,因为u的最大深度是Olog u,v的最大深度是Olog v

一旦我们找到了祖先,我们可以计算u和v之间的路径,如下所示。计算从u到该祖先的路径,方法是反复从u移开一位,直到我们到达共同的祖先。用同样的方法计算从v到祖先的路径,然后将该路径与第一步中找到的路径反向。此路径的长度由O | log u-log v |给出,因此运行时为O | log u-log v |

另一方面,如果你只需要路径的长度,你可以把从u到LCAu,v和从LCAu,v到v的距离相加。我们可以在每个Olog log max{u,v}时间中计算这些值,因此运行时是Olog log max{u,v}


希望这有帮助

你能给我们提供更多的信息吗?最短路径是沿着目标节点的方向向上或向下移动,直到到达其分支,然后向上或向下移动,直到到达节点,不是吗?除非我误解了你的问题,在二叉树中从一个节点到另一个节点只有一种方法。因此,没有最短路径;这只是路径。你能给我们提供更多的信息吗?最短路径是沿着目标节点的方向向上或向下移动,直到到达其分支,然后向上或向下移动,直到到达节点,不是吗?除非我误解了你的问题,在二叉树中从一个节点到另一个节点只有一种方法。因此,没有最短路径;只有一条路。