• Text Editor 的 Piece Table 结构


    Text Editor 的 Piece Table 结构

     

    Charles Crowley 在 Data Structures for Text Sequences 中描述了一种用于存储和编辑文本的数据结构 Piece Table。这种结构被大多数 Professional 的文本编辑器/字处理器所使用。另一种广为应用的(更简单)的数据结构是 Gap,最初被用在 Emacs 中,现在的 Scintilla,Java Swing Text Field 等文本编辑组建都使用这种结构。Charles Crowley 的文章中有详细的关于这两种结构的性能比较。

    在处理大型文档的时候,“Piece Table + 缓存优化的 ItemAt 操作”的性能要高于“Gap”结构。开源字处理软件 AbiWord 就使用了这种结构。在 AbiWord 开发者的博客上有一个将 Piece Table 所有操作都提高到 O(log n) 的方法,参见 Improving the AbiWord’s Piece TableAbiWord 的开发计划里也有相应 Speed Up Piece Table 的计划。这里的优化方法是将本来用 Linked List 存储的 Piece 以 Red-Black Tree 代替,由此将 ItemAt 操作提高到 O(log n)。

    Piece Table 的结构由几部分组成:

    1. Sequence:

    Sequence 是整个数据结构的接口,用户程序唯一的访问方式。逻辑上 Sequence 由一系列 Item 组成。Item 是存储和操作的最基本单元,在文本编辑器中可以与 Character 对应。Sequence 所能提供的操作与 List 相同,包括:Insert, Delete, Replace, ItemAt, Undo/Redo 等。物理上 Sequence 并不直接存储 Item(Item 存储在最后一层 Buffer 中),Sequence 存储的是一系列的 Piece Descriptor。每个 Piece Descriptor 指向了一个 Piece。

    Sequence 和 Piece Table 是等价词。Sequence 用来讨论逻辑结构(接口)而 Piece Table 用来说明物理结构(实现)。

    2. Piece:

    Piece 是一组连续的 Item。这里的连续有两层意义,逻辑上连续和物理上连续。简单说 Item Index in Sequence 的连续是逻辑连续,而 Item Offset in Buffer 的连续是物理连续。Piece 中的 Items 既是逻辑连续又是物理连续。有些文章里将 Piece Descriptor 称为 Piece,而将 Piece 称为 Span。Piece 的成员包括:指向 Buffer 的指针,在 Buffer 中的 Offset,以及长度 Length. 每次添加操作都会增加一个新的 Piece,根据情况有可能将旧的 Piece 拆分成两个。每次删除操作也会相应的 Piece 删除或拆分。

    3. Buffer:

    Buffer 是真正存储 Item 的地方。在 Charles Crowley 的文章中 Piece Table 仅仅包括两个 Buffer,一个存储整个被编辑的文件,另一个存储添加的字符(被删除的字符也保留在 Buffer 中,可用于 Undo/Redo)。第一个 Buffer 是 Fixed Length 的,而第二个 Buffer 是 Append Only 的。试作中我们可以使用多种方法优化这两种 Buffer。

    可以看出对于 Sequence (Piece Table) 所有的添加删除操作本身都是 O(1),与 Linked List 相同。但其访问操作(ItemAt)是 O(k),这里 k 为 Piece 的数量。这是由于我们使用 List 或 Array 存储 Piece Descriptor。我们也注意到所有的添加删除操作都需要先找到相应的 Piece,而这个操作也是 O(k) 的,这时我们可以简单的将最近一次访问的 Piece 缓存起来来大幅度提高性能。这也是 AbiWord 的做法。对于 O(k) 的操作我们可以尽可能的减少 k (Piece 的数量),最简单的方法是避免每个字符插入操作都产生一个 Piece,将一系列连续的插入删除操作产生一个 Piece。

    更高级的优化技术是将 List 结构的 Piece Table 转换为 Red-Black Tree 结构。每个 Tree Node 包含:一个 Piece,其左分支的所有 Piece 的 Length (注意与 Index in Sequence 不同)。

  • 相关阅读:
    Python学习札记(十五) 高级特性1 切片
    LeetCode Longest Substring Without Repeating Characters
    Python学习札记(十四) Function4 递归函数 & Hanoi Tower
    single number和变体
    tusen 刷题
    实验室网站
    leetcode 76. Minimum Window Substring
    leetcode 4. Median of Two Sorted Arrays
    leetcode 200. Number of Islands 、694 Number of Distinct Islands 、695. Max Area of Island 、130. Surrounded Regions 、434. Number of Islands II(lintcode) 并查集 、178. Graph Valid Tree(lintcode)
    刷题注意事项
  • 原文地址:https://www.cnblogs.com/songtzu/p/3539789.html
Copyright © 2020-2023  润新知