【问题标题】:Is there any faster implementation for this Splay Tree range sum?这个 Splay Tree range sum 有没有更快的实现?
【发布时间】:2016-08-08 08:24:41
【问题描述】:

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

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 变量,在调用summation 函数之前初始化为0st & ed 这两个参数定义了范围(包括)。

summation 函数的工作复杂度为 O(n)。任何人都可以为此建议更快的实现吗?

【问题讨论】:

  • void summation(Node *R, ...) Node 不是类型名称。你在用 C++ 吗?
  • Node 是我在问题前面提到的结构。
  • 既然你不知道你一定是在使用 C++。 (在 C 中,struct Node {...}; 确实 not 暗示 typedef struct Node{...};

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


【解决方案1】:

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

https://ideone.com/aQgEpF

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

这里的关键思想是使用拆分和合并,提取覆盖范围的子树。此外,每个节点都包含一个字段sum,它是其子树中所有键的总和。 sum 字段是惰性求值的,并且仅在拆分操作期间(沿拆分线)进行中继,这样就不会深入到不需要计算的级别。

【讨论】:

  • 非常感谢!这正是我想要做的!我有这个想法,但无法在代码中实现。再次感谢!
【解决方案2】:

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

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

基本思路如下:

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

  2. 经过一番思考,您可以了解如何在更新树时有效地更新此信息。

  3. 进一步思考,您可以了解如何使用此元数据回答范围查询。

【讨论】:

  • 感谢第一段中给出的建议。我会记住这一点。 :) 而且,也感谢您的想法。这对我帮助很大!
  • 不客气。另一个答案基本上是这个的实现,顺便说一句。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
相关资源
最近更新 更多