【问题标题】:Pick random node from tree从树中选择随机节点
【发布时间】:2013-01-20 12:28:47
【问题描述】:

我有一个树形数据结构,其中每个节点可以有多个子节点。因此,不仅有左和右,而且更少甚至更多。 现在我想从这棵树中随机选择一个节点。对于每个节点,我知道有多少孩子连接到它。但是我怎么能以随机的方式挑选它们,统一会很棒。有任何想法吗?我找到了只有左孩子和右孩子的情况的解决方案,但正如我所说,这在这里并不适用。

【问题讨论】:

  • 您是只对挑选 leaf 节点感兴趣,还是希望同时挑选 branch 节点?
  • 其实我对弧很感兴趣,但是当我有节点时,我会选择进入节点的弧。所以换句话说,不只是叶子,任何节点都应该是可能的。

标签: java data-structures random tree


【解决方案1】:

这是一个可能有用的观察结果:假设您以某种方式对树中的所有节点进行编号,这样可以有效地查找某个任意 n 的第 n 个树节点。如果你能做到这一点,那么你可以通过选择一个随机节点号来有效地选择一个随机节点,然后去那个节点。

执行此操作的一个非常简单的方法是执行 DFS 或树的其他遍历并将所有节点存储在动态数组中。然后,您只需索引数组即可进行 O(1) 时间随机采样。但是,这有 O(n) 的内存开销,如果树不断变化,那就不好了。

如果树正在快速变化,另一种对节点进行编号以减少重新计算索引所需时间的方法如下。首先将根节点编号为 0。然后,对第一个子树中的节点进行递归编号,然后是第二个,依此类推。您可以通过让每个树节点将节点总数存储在以该节点为根的子树。这样,要查找树中的第 n 个节点,您可以执行以下操作:

  1. 如果 n = 0,则返回根节点。
  2. 否则,设置 n = n - 1,然后从左到右依次循环遍历当前节点的子节点,如下所示:
    1. 设 k 为子树中的节点数。
    2. 如果 n
    3. 否则,设置 n = n - k。

如果您有一个具有合理分支因子的相对平衡的树,则此方法运行速度非常快,因为您可以快速丢弃树中不包含第 n 个元素的部分。

使用这种方法,您可以获得一种非常快速的方法(虽然不是 O(1)),用于从树中挑选第 n 个元素:选择一个随机索引,然后返回该索引处的节点。此外,即使在树中添加或删除节点,这也有效。每当插入一个节点时,只需增加从根到该节点的路径上所有节点的计数。每当一个节点被删除时,减少从根到被删除节点的路径上所有节点的计数。

不过,这种方法仍然使用 O(n) 开销来存储计数。对于在线性时间内运行的 O(1) 开销算法,请查看 @NPE 基于水库采样的出色解决方案。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    如果均匀分布很重要,您可以遍历树并使用reservoir sampling

    但是,这种方法的时间复杂度与节点数量呈线性关系。

    【讨论】:

    • 好的,我现在阅读了水库采样,但我不明白你的想法。假设我在树的根节点,我可以看到它有 4 个子树。第一个包含四个更多节点,第二个 3 第三个 2 和第四个 4 再次。好的,现在呢?我猜我的 n 是节点的总数。但是什么是k?我什么时候知道应该选择某个节点?
    • @user1994555:如果你只想要一个号码,k=1。如果你想要五个数字,你可以使用k=5
    • 好的,但是我怎么知道我应该选择一个节点呢?你知道,它什么时候停止?
    • @user1994555:你已经遍历了整个树。最后,您将在水库中拥有k 元素,这是您的随机样本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 2017-10-02
    • 1970-01-01
    相关资源
    最近更新 更多