【问题标题】:Rope data structure & Lines绳索数据结构和线条
【发布时间】:2021-03-31 19:16:28
【问题描述】:

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

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

但是,我如何获得特定行(在这种情况下为\n)的开始位置?例如,我如何获得第 15 行的开始位置?我可以看到几个选项。

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

问题

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

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

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

我正在考虑使用BST,更具体地说是RB-Tree,但我不完全确定这将如何工作。我看到 VSCode 做了 this 但用 PieceTable 代替。

任何帮助将不胜感激。

编辑

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

我还注意到ropey,它是Rope 的锈库。我想知道除了C++之外是否有类似的东西。

【问题讨论】:

  • 您是否考虑将数据存储为表示线条的字符串向量?
  • @StefanHaustein 对于连接、子串、插入等操作,不会有绳索的 O(logn) 复杂度。相反,它们都需要线性时间。

标签: c++ data-structures text ropes


【解决方案1】:

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

然后查找特定的换行符将与查找包含特定字符索引的节点完全相同。您将查看“换行数”字段而不是“字符数”字段。

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

【讨论】:

  • 感谢您的回答!我要试试这个并报告
  • 我很好奇,如果行是 CRLF,并且有 2 个叶节点,其中一个叶节点包含 CR,另一个包含 LF,我怎么知道它只有 1 行而不是 2 个单独的行?
  • @WowThere 您可以只计算 LF 而忽略 CR。
  • 但是如果我计算 CR、LF 和 CRLF 呢?
  • @WowThere 我没有看到这样做的好处。仅 LF 就足以告诉您行的开始位置。
猜你喜欢
  • 1970-01-01
  • 2013-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 2016-08-28
相关资源
最近更新 更多