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

时间:2012-08-06 01:51:41

标签: algorithm

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

如果我在list1的索引0处插入一个新数字,比如数字2,我必须更新list2中的所有后续值。对于非常大的列表,这非常耗时(也违背了第二个列表的目的)。

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

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

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

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

2 个答案:

答案 0 :(得分:1)

在没有树的情况下执行此操作的一种简单方法是将主数组分别拆分为sqrt(N)元素的sqrt(N)区域。对于每个部分,记录它所覆盖的范围以及该范围内元素的总和。现在,如果要查找元素k的总和,可以将元素k之前的所有sqrt(N)大小的范围的和加在一起,然后将元素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))工作。

答案 1 :(得分:0)

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

相关问题