为什么在算法中使用子树大小来选择二叉树中的随机节点?

2024-04-19

我偶然发现了从二叉树中选择随机节点的算法的几种实现,它们都使用子树大小属性。但是,我不明白为什么知道子树大小有帮助。这是实现A https://stackoverflow.com/a/32011526 and B https://www.geeksforgeeks.org/select-random-node-tree-equal-probability/.

总体思路可以用这个伪代码来描述:

Node getRandomNode() {
    Random seed = new Random;
    int random = random.nextInt(this.size);

    if (this.left.size == random)
        return this;
  
    if (this.left.size > random) {
        return this.left.getRandomNode();
    } else {
        return this.right.getRandomNode();
    }
}

我假设getRandomNode()方法总是在树的根部调用。

据我所知,选择节点的随机性仅取决于random整数。在某些情况下如果random然后重演getRandomNode()将返回相同的节点。

我也不明白该算法如何在完整的二叉树中工作。每个节点子树的大小始终是偶数。因此,如果random是一个偶数,算法将不会在这一行匹配:

if (this.left.size == random)
        return this;

并且只会产生一个随机数,如果random是偶数,这意味着该算法不是随机的。

我错过了什么吗?

如果我必须实现该算法,我只需存储一个附加链表,其中每个节点都有一个索引(例如ArrayList在Java中),然后从列表中返回其索引等于从返回的随机数的节点random.nextInt().


感谢您在这里概述了您的思维过程。让我们一步一步地回顾一下您在这里所说的内容。

我假设getRandomNode()方法总是在树的根部调用。

它总是在根上被调用some子树,但它不一定是整个树的根。例如,考虑这个简单的树:

                  A
                 / \
                B   C
                   / \
                  D   E

在这里,第一个电话将是A.getRandomNode(),它将从以 A 为根的子树中选择一个随机节点。之后,我们有 1/5 的机会从左子树中请求随机节点,有 3/5 的机会我们从左子树中请求随机节点右子树的,并且我们停止并返回 A 的机会为 1/5。为了论证,假设这里生成的随机数是 4,并且我们决定在右子树中查找。这意味着下一个电话是C.getRandomNode(),它要求从这棵树中随机选择一个节点:

             C
            / \
           D   E

在这里,我们将生成一个随机数,其中有 1/3 的机会从左子树请求随机节点,有 1/3 的机会从右子树请求随机节点,还有 1/3 的机会从左子树请求随机节点。以 C 停止。为了论证,假设我们生成随机数 0 并向左走。这叫D.getRandomNode(),它要求该子树中的一个随机节点:

               D

这个调用总会返回D,因为这是唯一的选择。

希望这能让您对算法的工作原理有更多的了解。在每个时间点,我们希望有平等的机会选择任何元素。因此,我们决定是停止、向左还是向右,根据每个选项中的节点数量来衡量我们的选择。

据我所知,选择节点的随机性仅取决于随机整数的随机性。在某些情况下,如果随机重复的话getRandomNode()将返回相同的节点。

你是对的,这里随机性的唯一来源是选择哪个随机整数。这是有道理的,因为树本身不是随机的。

话虽这么说,您在此处展示的实现会在沿着树向下走的每个步骤中进行单独的随机计算。因此,多个不同的随机选择都必须走同样的路,才能得到与结果相同的节点。

我也不明白该算法如何在完整的二叉树中工作。每个节点子树的大小始终是偶数。因此,如果 random 是偶数,则算法将不会在这一行匹配:

if (this.left.size == random)
     return this;

如果 random 是偶数,则只会产生随机数,这意味着该算法不是随机的。

你是对的,如果我们只是生成一个随机数并在整个过程中使用该数字,那么是的,你会遇到这样的麻烦。然而,这并不是算法的工作原理。相反,每次我们递归调用getRandomNode(),我们选择一个新的随机数并用它来进行路由。因此,无论我们选择的第一个数字是偶数还是奇数,我们最终都会到达唯一选择是返回当前节点的位置,此时我们将返回一些内容。

如果我必须实现该算法,我只需存储一个附加链表,其中每个节点都有一个索引(例如ArrayList在Java中),然后从列表中返回其索引等于从返回的随机数的节点random.nextInt().

这样你绝对可以解决问题。如果您正在使用的树永远不会改变 - 没有添加或删除任何内容 - 那么这是一个完全合理的策略。

标记子树大小的方法很有用的原因是,即使添加或删除节点,它也可以让您从树中随机采样。具体来说,您可以相当快速地调整存储在每个节点中的数字,以响应节点的插入或删除,这比必须在节点中重建或打乱元素要快得多。ArrayList是树改变形状。查看顺序统计树 https://en.wikipedia.org/wiki/Order_statistic_tree有关如何执行此操作的更多详细信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在算法中使用子树大小来选择二叉树中的随机节点? 的相关文章

  • 尝试让 GUI 使用 arrayList 在牌组中打印随机卡

    所以我目前正在用java开发一个卡牌战争游戏 我试图让 GUI 屏幕使用 arrayList 从一组卡片图像中打印 2 张随机卡片 必须使用它进行分配 卡片图像文件名为 1 png 2 png 52 png 并存储在 image card
  • 如何使用 Android Studio 2.1.3 从 Android 中的文本文件中获取随机行?

    我有一个 500 行的文本文件 我将此文本文件放置在 app src main assets 文件夹中 名称为 words txt 在此文件中 每一行都用换行符分隔 现在我需要从这个文本文件中获取随机行 在发布此内容之前 我访问了以下问题
  • 树中的节点是否被视为其自己的祖先?

    我想知道计算机科学背景下对 祖先 定义的共识是什么 我问只是因为在算法简介 http en wikipedia org wiki Introduction to Algorithms 第二版 第 14 页 第259章 有算法的描述Tree
  • 将区间映射到更小的区间的算法

    我尝试搜索 但由于问题的性质 我无法找到满意的内容 我的问题如下 我试图将 0 到 2000 范围内的数字 尽管理想情况下上限是可调的 映射到 10 到 100 范围内的更小的区间 上限将映射 2000 gt 100 和下限也是如此 除此之
  • 比较周期性数据的快速方法

    假设我有任意类型的数据集 A B C D 并且我想将其与另一个数据集进行比较 我希望 A B C D B C D A C D A B 和 D A B C 的比较成立 但是不适用于 A C B D 或任何其他未类似排序的集合 有什么快速方法可
  • 生成非连续组合

    我正在尝试创建一个生成器 支持执行 next 的迭代器 可能在 python 中使用yield 它给出来自 1 2 n n 和 r 是参数 的 r 元素的所有组合 这样在选出的r个元素 没有两个是连续的 例如 对于 r 2 且 n 4 生成
  • 无痛“算法分析”培训? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我在大学时曾有过一次关于 算法分析 课程的痛苦经历 但最近发现在大学中需要它真实世界 无论如何 我正在
  • 如何使用 NumPy/SciPy 进行简单的高斯混合采样和 PDF 绘图?

    我添加三个正态分布以获得一个新的分布 如下所示 如何在python中根据这个分布进行采样 import matplotlib pyplot as plt import scipy stats as ss import numpy as np
  • 如何最小化两个子多边形的最大纵横比?

    我想使用直线将凸多边形切成给定面积比的两部分 以使两个子多边形的较大纵横比最小化 目前我的方法包括选择一个随机起点 计算将多边形分割成目标区域的适当终点 然后计算两个纵横比中较大的一个 然后重复这个很多次 直到我足够接近最小值 多边形 A
  • 修改排列算法以防止重复打印输出的策略

    我一直在审查实践算法 目前正在研究一种我非常喜欢的排列算法 void permute char set int begin int end int range end begin if range 1 cout lt lt set lt l
  • O(mn) 比 O((m+n)^2) 更好吗?

    算法的输入是m and n 我的算法的时间复杂度是O mn 我有一个时间复杂度为的基准算法O m n 我的实现在时间复杂度方面是否优于基准 许多评论者和回答者希望只考虑以下情况 m n或者至少当它们通过一个常数因子相关时 这不是它的工作原理
  • 给定与总和匹配的长度的唯一 3 位数字 (-1,0,1) 序列的数量

    假设您有一个长度为 n 即空格数 的垂直游戏板 你有一个三面骰子 有以下选项 前进一 停留和后退 如果您低于或高于棋盘游戏空间的数量 则该游戏无效 一旦到达棋盘末端 唯一有效的动作就是 停留 给定确切的骰子投掷次数 t 是否可以通过算法计算
  • 如何找到最长的回文子序列(不是它的长度)

    我想找出字符串中最长的回文子序列 我到处都找到了找出子序列长度的算法 并声明该算法也可以扩展以返回子序列 但我没有找到如何实现的 有人能解释一下我怎样才能得到序列吗 既然你提到了链接最长回文子序列 http www geeksforgeek
  • 4 x 3 锁图案

    我遇到了这个 它要求计算在 4x3 网格中可以制作特定长度的锁定图案的方式数 并遵循规则 可能有些点不能包含在路径中 有效的模式具有以下属性 图案可以使用第一次接触的点序列来表示 与绘制图案的顺序相同 从 1 1 到 2 2 的图案与图案不
  • 我想优化这个短循环

    我想优化这个简单的循环 unsigned int i while j 0 j is an unsigned int with a start value of about N 36 000 000 float sub 0 i 1 unsig
  • R:如何添加具有从矩阵的每一行中随机选择的值的列?

    我会先说我是一个 R 菜鸟 我认为这可能有一个简单的解决方案 但我正在努力寻找它 我有一个 2 列 1 000 行的矩阵 保持行固定 我想创建一个新变量 从两列中随机选择一个元素 例如制作一个简单的矩阵 matrix c 1 1 4 6 1
  • 生成所有可能的树

    给定以下数据类型定义 data FormTree Empty Node FormTree FormTree deriving Show 我想编写一个函数 它生成一个无限列表 其中包含按长度排序的所有可能的树 例如节点数量 下面的代码几乎满足
  • 如何设置K-means openCV c++的初始中心

    我正在尝试使用 OpenCv 和 Kmeans 对图像进行分割 我刚刚实现的代码如下 include opencv2 objdetect objdetect hpp include opencv2 highgui highgui hpp i
  • 交换两个向量之间的值,使两个向量的 max_element 之和最小

    这是 Codechef 的问题 但请耐心等待 https www codechef com ZCOPRAC problems ZCO16001 https www codechef com ZCOPRAC problems ZCO16001
  • 无需时间即可生成随机字符串?

    我知道如何使用 Runes 和播种 rand Init 在 go 中生成随机字符串time UnixNano 我的问题是 是否可以 使用 stdlib 在不使用当前时间戳 安全 的情况下播种 rand 此外 我问 因为仅仅依靠时间来为敏感操

随机推荐