【问题标题】:Dynamic (i.e. variable size) Fenwick Tree?动态(即可变大小)Fenwick Tree?
【发布时间】:2014-02-24 18:26:57
【问题描述】:

问题: 我偶然发现了可以轻松计算累积总和的 Fenwick 树(二进制索引树)。但是,我只找到了叶数(总和)是恒定的(但它们的值可以改变)的实现。 是否存在类似于广义 Fenwick 树的东西,它允许改变叶子(总和)的数量,即具有可变大小?

背景 我目前正在编写一些随机模拟代码(在 C++ 中):瓮中有球,每个球 i 都有一定的概率 p_i 被绘制。在绘制事件时,一个球被绘制(并移除)并被两个具有新概率的新球替换(并且所有概率都相应地重新调整;我已经有效地“重新调整”了,所以不要打扰它)。在某个时候,我开始移除球,使球的数量围绕一个恒定值波动(这是之前已知的)。为了有效地进行绘图,我想使用二叉树。标准的 Fenwick 树完全符合我的要求,只是它不允许改变瓮中球的数量。

典型数字 从 10 个球开始,添加球并在大约 1000 个时开始移除球,这样骨灰盒中的球在 900 到 1100 个之间(即添加和移除球,使数量保持在 1000 左右)。

目前的解决方法 估计需要的最大球数(有一定的安全余量,比如 1200 个球),并使恒定大小的 Fenwick 树变大,其中大多数球最初被抽出的概率为 0 并被连续更新。

非常感谢您的帮助! 马蒂亚斯

【问题讨论】:

    标签: c++ algorithm tree stochastic-process


    【解决方案1】:

    实际上,正常(没有以任何方式概括)Fenwick 树允许随时增加叶子的数量。

    某些特定的实现可能不允许这样做。但这可以解决。例如,implementation from TopCoder 不允许更改叶子的数量。问题是update 函数从给定索引开始修改数组元素并向上,当它达到某个限制(MaxVal)时停止,在我们的例子中是事先不知道的。 read 函数向下迭代数组元素,因此它不需要知道当前数组的大小。如果我们在updateread之间交换数组迭代代码,这个问题可以解决:现在update不需要知道MaxValMaxValread中使用,我们可以使用最大的更新索引至MaxVal

    int read(int idx){
        int sum = 0;
        while (idx <= MaxVal){
            sum += tree[idx];
            idx += (idx & -idx);
        }
        return sum;
    }
    
    void update(int idx ,int val){
        while (idx > 0){
            tree[idx] += val;
            idx -= (idx & -idx);
        }
    }
    

    注释。

    1. 与 TopCoder 的实现不同(read 返回前缀总和),此实现提供后缀总和。如果您需要前缀和,只需从值的总和中减去 read 返回的值即可。
    2. 我选择了这个实现,因为 (1) 它是对知名 TopCoder 实现的简单修改,并且 (2) 它以非常对称的方式更新索引,因此只需将“+”更改为“-”即可从前缀到后缀。
    3. 否则我宁愿在索引计算中使用不同的按位运算。恕我直言,此博客:Fenwick trees demystified 提出了一个更好的选择,每次索引更新只有 2 次操作,而不是 3 次(但还需要一些修改以允许可变大小)。如果兼容性不是问题,我们可以通过使用一些特定的指令来做得更好,例如英特尔最近的指令集 (BMI1) 中的 BLSR

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-07
      • 1970-01-01
      • 2016-12-24
      • 1970-01-01
      • 2018-11-16
      • 2011-01-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多