在C++中有什么类似Haskell Data.Sequence的吗?

wil*_*lir 6 c++ tree haskell data-structures

是否有任何C++库实现Haskell Data.Sequence容器之类的东西?

我最感兴趣的是:

  1. 维护元素顺序(插入它们的顺序).
  2. O(logn)通过索引访问.阿卡operator[](size_type pos).
  3. O(logn) 在中间插入/删除(通过索引).

Cri*_*ngo 4

在我看来,实现*这种数据结构的方法需要一棵树来存储每个节点中的元素数量。它允许在 O(log(N)) 中插入和检索,并且只需计算树中给定节点“左侧”有多少个元素即可维护索引。

\n

*我在这里回答的问题可能略有不同,实际的问题要求推荐一个库,这显然是偏离主题的。

\n

该树的一个节点如下所示:

\n
template<typename T>\nstruct Node {\n  Node* left;\n  Node* right;\n  size_t elements;\n  T value\n  \n  T& access(size_t index) {\n    if (left->elements == index) {\n      return value;\n    } else if (left->elements > index) {\n      return left->access(index);\n    } else {\n      return right->access(index - left->elements - 1);\n    }\n  }\n\n  void insert(size_t index, T&& value) {\n    // insert `value` at right place, increment `elements`\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

(我将该insert方法留给读者作为练习。)

\n

编辑:正如 willir (OP) 在下面的评论中提到的,该树需要是一棵平衡树。Arne Vogel 建议 B 树是缓存局部性的最佳选择。

\n
\n

但:

\n

如果您确实实现了类似的功能,请确保测量您的应用程序,并将其与std::vector. 在任意位置插入向量的时间复杂度为 O(N),而不是 O(log(N)),但它是一个非常便宜的操作 O(N)。与此类数据结构相比,向量具有许多优点:

\n
    \n
  1. 无需维护代码。

    \n
  2. \n
  3. 需要存储的内容更少(在树中,您需要存储两个指针和一个计数,这在向量中是不必要的),这意味着更多的数据可以同时放入缓存中。

    \n
  4. \n
  5. 数据的访问顺序始终与存储的顺序相同。对于树,您需要遍历可以存储在内存中任意位置的节点,它们不需要靠近在一起,并且可能不按照读取的顺序存储。

    \n
  6. \n
\n

第 2 点和第 3 点意味着向量的缓存未命中次数要少得多。这可能会导致时间上的巨大差异。

\n

如果每个数据元素都很大,则在向量中移动数据会变得相当慢。但在这种情况下,您应该在向量中保留指向数据的指针,以便您移动指针列表,而不是实际数据。对于如此大的数据元素,我建议独立分配每个数据元素,并将其指针保存在std::vector<std::unique_ptr<T>>.

\n

以下是一些相关链接:

\n\n

  • 是的,还有,仅仅二叉树是不够的。你需要保持平衡。所以红黑树、Splay 树或 B 树。(我之前通过 Splay Tree 实现过这样的事情,但不是用于实际项目)。正如 @ArneVogel 所提到的,B 树会更好,因为它应该对缓存更友好。标准分配器支持是另一件需要记住的事情。这就是我询问图书馆的原因 - 如果您想自己实现它,有很多事情需要注意。 (2认同)