C++ 文本编辑器中的行管理

C++ 文本编辑器中的行管理,c++,winapi,data-structures,C++,Winapi,Data Structures,我在一个文本编辑器上工作了一段时间。我从头开始做了一个自定义编辑控件,现在我已经掌握了基本知识。我面临的问题是关于直线管理。因为,我的程序依赖于将输入文本分成几行(文本是逐行打印的),所以行管理非常重要。我使用std::vector来存储行位置。我使用一个片段表进行文本处理,但是为了简单起见,假设我有一个字符数组。每次用户按enter键时,我都会在线向量中添加/插入一个元素。问题是,每次用户插入字符时,整个结构都会受到干扰。例如: 0 1 2 3 4 5

我在一个文本编辑器上工作了一段时间。我从头开始做了一个自定义编辑控件,现在我已经掌握了基本知识。我面临的问题是关于直线管理。因为,我的程序依赖于将输入文本分成几行(文本是逐行打印的),所以行管理非常重要。我使用std::vector来存储行位置。我使用一个片段表进行文本处理,但是为了简单起见,假设我有一个字符数组。每次用户按enter键时,我都会在线向量中添加/插入一个元素。问题是,每次用户插入字符时,整个结构都会受到干扰。例如:

         0   1   2   3   4   5    6   7   8   9   10
text = ['h','e','l','l','o','\n','W','o','r','l','d']
state of line vector : 
line[0] = 0 
line[1] = 6
假设用户在文本[2]后插入一个字符('x'):

         0   1   2   3   4   5    6   7   8   9   10  11
text = ['h','e','l','x','l','o','\n','W','o','r','l','d'] 
state of line vector : 
line[0] = 0 
line[1] = 6
由于插入,我需要在当前行之后更新lines向量中每个元素的值。删除时也一样。如果一个程序中有1000行,用户编辑第一行,那么更新所有999个元素(第一行除外)的效率将非常低

我想的是让每条线彼此独立。但如果将现有线路分为两条线路,则会导致复杂情况。所以我想知道解决这个问题的好方法是什么

编辑: 我只是想澄清一下,我使用了一种称为piecetable的数据结构。我没有使用字符数组。以下是工件表数据结构的含义: 矢量将正常工作

考虑动态分配该行,并让向量存储指向该行的指针。将一堆指针移动到行比移动行本身要便宜得多


您也可能想考虑某种类型的

< P>许多编辑器使用的经典数据结构是“”。这基本上有一个工作空间,位于活动发生的光标周围,以便本地操作快速发生。然后,当光标移动时,如果发生更改,间隙将随之移动

就行计算而言,现代系统速度足够快,您几乎可以简单地扫描缓冲区并查找行。好的方面是,在大多数操作中,您不需要这样做,因此您可以一直避免这样做。此外,缓冲区中的物理行(即以EOL标记结尾的字符集合)和软行(ala字换行等)之间也存在差异。考虑一个现代文字处理机,其中段落通常是单一的“行”,但包裹到页边距。当然,你可以用任何一种方法来处理

最后,对于键盘上的大多数操作,您可以简单地使用相对位置(即,如果插入新行,则可以直接将新行标记添加到行数组中,因为您已经知道缓冲区中的点)。但是当你做一个大的粘贴操作,比如说,几行的时候,把它全部塞进并重新计算整个缓冲区可能会更快(作为一种替代方法,你可以把粘贴分成几行,然后在后台一行一行地插入,就像普通的行一样)


对于巨大的巨大缓冲区,或者缓慢的慢速计算机,你可能想考虑不要太担心全局状态(确切地说,缓冲区中有多少行,确切地说,你可能在哪一行上),在任何一点上,启动这种重新计算到背景中。最有可能的是停顿会很小(但如果你在打字,会很烦人),并且会在人们只是停顿下来捕捉他们的想法时立即出现。很明显,这会使设计复杂化,目前在现代硬件上使用蛮力可能还可以。

如果我理解这个问题,您将使用辅助数据结构跟踪这些线路的位置:

line  offset  length
   0       0      65
   1      65      30
   2      95      50
   3     145       1
   4     146      13
 ...
如果行n的长度更改了d,则必须将所有剩余行的偏移量更改为d。当有很多线的时候,这是很慢的

你可以追踪地标。偏移不是从序列的开始,而是相对于某个地标

假设每100行创建一个地标。由于第一个地标位于文件的开头,因此前100行的跟踪方式相同。但是接下来的一百行只是有偏移量,对于第100行,landmark具有从文件开头的绝对偏移量

因此,更改直线长度时,只需更新该地标中其余直线的偏移量,以及其余地标的偏移量。这仍然是O(n),但是有一个相当大的除数,它会使它更快


但我们可以做得更好。不只是维护一个地标列表,假设我们把它们放在一棵树中,树的叶子是你的线,根代表整个文件。要查找给定直线的偏移量,请将其所有祖先的偏移量相加。如果一条线发生变化,只需更新一个节点及其祖先。这就得到了O(logn),但需要一些簿记。空间开销并不比您已经使用的双链表严重。

如果您想支持廉价插入,显然vector是错误的数据结构选择。O(n)复杂性。你考虑过列表吗?@HansPassant如果你的意思是在列表中为每个元素存储一行,那么从一行移动到另一行会很昂贵(尽管无可否认,插入一行可能比从一行移动到另一行更常见),你还没有真正描述你试图解决的问题。例如,您需要O(1)访问第N行,还是O(N)访问?(如果是这样的话,您可以简单地将行的长度保留在向量中,并在必要时将它们相加。)@Neil我正在寻找一种相对有效的方法来实施行管理,同时记住,我需要为某些特定的对象对每行的长度进行公平的次数