Algorithm 如何最有效地划分不断变化的列表以计算其总和?

Algorithm 如何最有效地划分不断变化的列表以计算其总和?,algorithm,Algorithm,假设我有一个由4个不同值的数字组成的列表。我有第二个列表,描述到该点的所有数字的总和(如果list1=[1,3,2,5],list2=[1,4,6,11])。通过这种方式,对于数十万个数字的列表,我不必添加所有数字-信息已经存储 如果我在列表1的索引0处插入一个新的数字,比如数字2,我必须更新列表2中的所有以下值。对于非常大的列表,这会非常耗时(也会破坏第二个列表的用途) 但是,如果我记录列表(4)前半部分的和,我可以从相对于该和的位置继续list2(list2=[1,4,2,7])。现在,如果

假设我有一个由4个不同值的数字组成的列表。我有第二个列表,描述到该点的所有数字的总和(如果list1=[1,3,2,5],list2=[1,4,6,11])。通过这种方式,对于数十万个数字的列表,我不必添加所有数字-信息已经存储

如果我在列表1的索引0处插入一个新的数字,比如数字2,我必须更新列表2中的所有以下值。对于非常大的列表,这会非常耗时(也会破坏第二个列表的用途)

但是,如果我记录列表(4)前半部分的和,我可以从相对于该和的位置继续list2(list2=[1,4,2,7])。现在,如果我在index=0处插入数字2,我只需要更新前两个值和记录的中间值。对于100000个数字的列表,这将保证我只需要更新50000个值

我也可以在列表的每三分之一处记录值,或者每10000个数字记录一次值,或者我可以记录一半的值(有点像二进制排序-现在我只需要更新/查看我影响的任何子列表)

问题:我如何确定/管理此列表的最有效方式是什么?一半?三分之一?三个级别,每个级别将前一个级别减半


[这是一个实际问题,不是理论问题。列表2提供了布局和呈现文本/图形的偏移量。树在我工作的环境中不实用。我必须处理单个列表。我需要快速访问任何给定的总和/偏移量。此外,我很难清晰地表达它。请随时澄清问题估计或要求澄清。]

我会使用一个数组(C++中的向量),称之为IndexSum,它只包含和(您可以通过从和中减去之前的和来推断元素的值)。数组可以简单地建立索引,并且在顺序访问中表现良好。由于数组不保留指向下一个元素的指针,因此它们非常紧凑,并且很适合处理器数据缓存。我会将插入和删除保留在排序数组(向量)中,称之为InsertDeleteAdjust,您可以通过二进制搜索轻松访问它…这允许您跟踪需要对索引范围的IndexSum中的和进行的调整。您可以定期运行“垃圾收集”使用InsertDeleteAdjust中的值同步更新IndexSum的例程。如果这种周期性“垃圾收集”的延迟不可接受,那么您可以使用异步线程和锁等进行更高级的处理。

一种简单的方法是,在没有树的情况下,将主数组拆分为sqrt(N)的sqrt(N)区域每个元素。对于每个部分,跟踪它所覆盖的范围以及该范围内元素的总和。现在,如果您想找到元素k的总和,可以将所有sqrt(N)的总和相加调整元素k之前的范围大小,然后将元素k的范围中位于它之前的元素相加。这两件事都需要O(sqrt(N))时间,总共O(sqrt(N))

插入、删除和查询的所有操作都将是O(sqrt(N)),因为在每种情况下,您都需要查询/修改主数组中的O(sqrt(N))列表和O(sqrt(N))元素


您还需要偶尔对结构进行改革。具体何时进行改革取决于您,但您必须定期进行改革,否则您将无法在这些操作上保持O(sqrt(N))运行时。如果您在每次sqrt(N)修改(仅插入或删除)后完全重新生成列表,这就足够了。这需要O(N)每O(sqrt(N))项作业一次,随时间摊销后,将产生额外的O(sqrt(N))做每一项操作。

听起来你可能想要某种类型的树。谢谢。然而,虽然我理解我选择我的方法的原因可能并不明显,“为什么”在我的问题上几乎没有暴露出来。考虑到上下文,树不是一个可行的选项。你是否从列表中删除过数字?你如何访问列表,你是否在o中遍历它排序还是索引?在列表中插入新数字的频率是多少?访问列表的频率是多少?列表中的数字有多大?列表可以有多长?似乎最有效的方法是维护一棵树。树的每个节点都会维护列表特定范围的和,以及ild节点将维护子范围的总和。树可以在插入后的O(log(n))时间内更新,总和可以在O(log(n))时间内计算时间。@PuraVida:我确实删除了数字。我通过索引访问它。我访问它的次数远比编辑它的次数多,但编辑它时,我需要快速更新信息。数字通常在10-20之间,总和可以达到100万以上。列表通常有几十万项。