这个Splay Tree范围总和是否有更快的实现?

时间:2016-08-08 08:24:42

标签: c algorithm data-structures binary-search-tree splay-tree

我编写了一个展开树。节点就像这样表示。

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)。任何人都可以建议更快地实现这个??

2 个答案:

答案 0 :(得分:4)

这是我前段时间做的splay树实现,并针对SPOJ评估系统进行了测试(用C ++编写):

https://ideone.com/aQgEpF

此树实现支持您要求的内容(O(log(n))中的范围总和。

这里的关键思想是使用拆分和合并来提取覆盖范围的子树。此外,每个节点都包含一个字段sum,它是其子树中所有键的总和。 sum字段被懒惰地评估并且仅在拆分操作期间(沿着分割线)被中继,这允许不深入到不需要计算的级别。

答案 1 :(得分:1)

首先,作为旁注,让summation不返回任何内容,而不是操纵全局变量,probably not such a great idea。您可能应该考虑省略这个全局变量,并让递归函数返回它找到的内容(并且在返回此求和之前,有一个调用总结其进一步递归调用返回的值)。

关于您的具体问题,您可以按augmenting node metadata优化求和操作。这将减少求和操作的增长顺序,而不会影响其他操作的增长顺序。在不利方面,这将在一定程度上降低其他操作的速度。由你决定这种权衡是否对你有利。

基本思路如下:

  1. 在每个节点内保留另一个字段,表示以此节点为根的树中项目的总和。

  2. 经过深思熟虑,您可以看到在更新树时如何有效地更新此信息。

  3. 进一步考虑后,您可以看到如何使用此元数据回答范围查询。