我多次遇到过这个问题的变种,最近它成了算术编码器实现的瓶颈。给定从原点开始的已知非负大小S i 的N(< = 256)段,并且对于给定的x,我想找到n这样
S0 + S1 + ... + Sn-1 <= x < S0 + S1 + ... + Sn
问题在于查找和更新以大约相同的频率完成,并且几乎每次更新都是以段的大小增加1的形式。此外,段越大,它的概率就越高。查找或再次更新。
显然,某种树似乎是一种显而易见的方法,但我无法提出任何令人满意地利用已知域特定细节的树实现。
考虑到N的相对较小的尺寸,我也尝试了线性方法,但结果却比天然的二叉树慢得多(即使经过一些优化,例如从列表的后面开始,数字超过总数的一半) )
类似地,我测试了一个中间步骤,它重新映射值,以保持按大小排序的段,以便更快地访问最常用的,但增加的开销超过了增益。
很抱歉标题不清楚 - 尽管这是一个相当基本的问题,但我不知道它的具体名称。
答案 0 :(得分:1)
我想某些BST会这样做......您可以尝试向每个节点添加一个新的数字成员(int
或long
),以保留所有左后代的值的总和。然后你会在大致对数时间内寻找每个项目,一旦添加,删除或修改了一个项目,你就必须在递归的返回路径上更新它的祖先。您可以应用一些自组织树结构,例如AVL以保持最坏情况搜索最佳,或者应用splay树来优化对最常用项目的搜索。注意在重新平衡或展开期间更新左子树和。
答案 1 :(得分:1)
您可以使用二叉树,其中每个节点n包含两个整数A_n 和U_n,最初在哪里 A_n = S_0 + .. S_n和U_n = 0。
在任何固定的后续时间,让T_n = S_0 + .. + S_n。
当查找查询x的位置时,你会沿着树,知道对于每个节点m,当前对应的T_m值是A_m + U_m + sum_ {p:m的祖先,我们访问了正确的孩子p得到m} U_p。 这解决了在O(log(N))中的查找。
对于第n个间隔的更新(将其大小增加y),您只需在树中查找它,为您沿途访问的每个节点m增加U_m og y的值。这也解决了O(log(N))中的更新。