我编写了一个展开树。节点就像这样表示。
struct Node{
Node *l; /// The left Node
Node *r; /// The right Node
int v; /// The Value
};
现在,我需要知道树中所有数字在一定范围内的总和。为此,我实现了以下名为summation.
void summation(Node *R, int st, int ed)
{
if(!R) return;
if(R->v < st){ /// should not call left side
summation(R->r, st, ed);
}
else if(R->v > ed){ /// should not call right side
summation(R->l, st, ed);
}
else{ /// should call both side
ret+=R->v;
summation(R->l, st, ed);
summation(R->r, st, ed);
}
return;
}
ret
是一个全局int
变量,在调用0
函数之前初始化为summation
。两个参数st
&amp; ed
定义范围(包括)。
summation
函数的复杂度为O(n)。任何人都可以建议更快地实现这个??
答案 0 :(得分:4)
这是我前段时间做的splay树实现,并针对SPOJ评估系统进行了测试(用C ++编写):
此树实现支持您要求的内容(O(log(n))
中的范围总和。
这里的关键思想是使用拆分和合并来提取覆盖范围的子树。此外,每个节点都包含一个字段sum
,它是其子树中所有键的总和。 sum
字段被懒惰地评估并且仅在拆分操作期间(沿着分割线)被中继,这允许不深入到不需要计算的级别。
答案 1 :(得分:1)
首先,作为旁注,让summation
不返回任何内容,而不是操纵全局变量,probably not such a great idea。您可能应该考虑省略这个全局变量,并让递归函数返回它找到的内容(并且在返回此求和之前,有一个调用总结其进一步递归调用返回的值)。
关于您的具体问题,您可以按augmenting node metadata优化求和操作。这将减少求和操作的增长顺序,而不会影响其他操作的增长顺序。在不利方面,这将在一定程度上降低其他操作的速度。由你决定这种权衡是否对你有利。
基本思路如下:
在每个节点内保留另一个字段,表示以此节点为根的树中项目的总和。
经过深思熟虑,您可以看到在更新树时如何有效地更新此信息。
进一步考虑后,您可以看到如何使用此元数据回答范围查询。