通常'可扩展'网格表示为列表列表(行列表,每行包含单元格列表),这些列表是某种链接列表。
在这个数据结构中操作(删除,插入)行既简单又便宜,只需重新链接以前的节点,但是当涉及到列时,例如删除列就会变成一个非常长的操作,我需要“循环”所有行以删除索引单元格。显然,这不是好行为,至少在我的情况下。
我不是在说数据库;我发现这是一个很好的例子,它是文本编辑器中的一些文本文件,(据我所知)文本编辑器大多将行分成行,并且很容易删除行。我想删除一个列就像删除一些行一样便宜和高效。
最后,我需要的是一些多维网格,但我认为任何2D简单网格都适用于MD,我是吗?
答案 0 :(得分:1)
你可能有一个二维“链接矩阵”(我忘记了正确的术语):
... Col 3 ... Col 4 ...
| |
... --X-- ... --Y-- ...
| |
... ... ... ... ...
每个单元格有四个邻居,如图所示。此外,您需要可以指示行/列位置的行和列标题,以及指向每行或每列中的第一个单元格。这些最容易表示为没有向上邻居的特殊单元格(对于列标题)。
在3和4之间插入一个新列意味着在col 3中向下迭代单元格X,并插入一个新的右邻居Z.这个新单元格Z向左链接到X并向右链接到Y.您还需要添加一个新列标题,并垂直链接新单元格。然后,4之后的所有列的位置可以重新编号(第4列变为第5列)。
... Col 3 Col 4 Col 5 ...
| | |
... --X-----Z-----Y-- ...
| | |
... ... ... ... ...
插入列的成本是O( n )用于插入和链接新单元格,而O( m )用于更新列标题。这是一个类似的删除过程。
因为每个单元只有四个链接,所以相同的算法用于行插入/删除。
答案 1 :(得分:1)
保持现有数据结构不变。此外,在创建时为每列提供唯一的ID。删除列时,只需将其id添加到所有已删除列id的哈希表中。每次走一行时,检查每个元素的列id(需要与元素的所有其他数据一起存储)和哈希表,如果它已被删除,则将其拼接出行。
如果您有每个网格元素可以指向的每列数据结构,则不需要哈希表和ID。那么你只需要在该数据结构中删除一个位。
顺便说一句,Edmund的计划也适合你。即使删除长度为n的行或列需要花费O(n)时间,您可以将该成本与创建这n个元素的成本进行摊销,从而使删除O(1)摊销时间。答案 2 :(得分:0)
我知道“链接列表”通常从理论的角度来看,但在实践中它们通常效率低下。
我建议转向随机访问容器以获得一些速度。最简单的是一个数组,但是根据我们所讨论的数据大小,双端队列或索引跳过列表/ B *树可能会更好。
从概念上讲,它没有太大变化(但是),但是你能够移动到O(1)(array,deque)/ O(log N)中的给定索引(跳过列表/ B *树)操作,而不是带有简单链接列表的O(N)。
然后是神奇的时间。
Keith已经暴露了这个基本想法:您只需要将其标记为已删除,然后在行走结构时“跳转”在其上方,而不是实际删除该列。但是,哈希表需要线性遍历才能到达第N列。使用Fenwick树将产生一种计算真实指数的有效方法,然后您可以直接跳转到那里。
请注意,将行标记为已删除的主要好处是undo
操作的明显可能性。
另请注意,您可能需要构建一个压缩函数,以便不时删除已删除的列,而不是让它们累积。