绳索数据结构和线条

Rope data structure & Lines

本文关键字:数据结构      更新时间:2024-05-09

我正在使用绳子来存储大量(GB)的文本。文本可以长达数千万行。

绳索本身在任何位置插入的速度都非常快,并且在特定位置也快速获得角色。

但是,我将如何到达特定行(在这种情况下n)的起点?例如,如何到达第 15 行的起点?我可以看到几个选项。

  1. 没有任何额外的数据。每当你想说第 15 行时,你遍历Rope中的所有字符,找到换行符,当你到达第 15 行时,你就会停止。
  2. 将每行的startlength存储在向量中。因此,您将拥有包含所有字符的Rope数据结构,然后是一个单独的std::vector<line>line结构仅包含 2 个字段;startlength.开始表示直线在Rope内的位置,长度是直线的长度。要到达第 15 行的起点,只需lines[14].start

问题

#1 是一种可怕的方法。它非常慢,因为你必须遍历所有的角色。

#2也不好。虽然到达一行的起点非常快(O(1)),但每次插入一行时,都必须将所有行移到它前面,这O(N)。此外,存储这意味着对于您拥有的每一行,它都会额外占用 16 字节的数据。(假设startlength各为 8 个字节)。这意味着如果您有 13,000,000 行,它将占用 200MB 的额外内存。您可以使用链表,但这只会使访问变慢。

有没有更好、更有效的方法来存储行位置以便快速访问和插入?(最好是O(log(n))用于插入和访问行)

我正在考虑使用BST,更具体地说是RB树,但我不完全确定这将如何与之配合使用。我看到VSCode这样做,但用了PieceTable

任何帮助将不胜感激。

编辑

@interjay提供的答案似乎不错,但如果 CR 和 LF 在 2 个叶节点之间拆分,我将如何处理 CRLF?

我还注意到 ropey,这是一个Rope的生锈库。我想知道是否有类似的东西,但对于C++.

在每个绳索节点(叶子和内部节点)中,除了保存该子树中的字符数外,还可以放置子树中包含的换行符总数。

然后,查找特定的换行符的工作方式与查找具有特定字符索引的节点完全相同。您将查看"换行符数"字段而不是"字符数"字段。

所有绳索操作的工作方式基本相同。创建新的内部节点时,只需添加其子节点的换行符数。所有操作的复杂性都是相同的。