我想存储分层有序列表。一个例子是嵌套的待办事项列表。另一个例子是XML。它只是一棵树,孩子们在这里。为简单起见,条目只是文本字符串。
问题是用户会编辑列表,因此常见操作很快很重要:
我可以想象如何在数据结构中执行此操作:条目是链接列表,如果它们包含子项,则它们也指向另一个链接列表的头部。有一个哈希表将条目id与实际数据相关联。
但是,我需要存储数据,我不知道如何实现这一点。如果只有一个元素发生变化,我不想保存整个树。什么是最好的方法?平面文件/ SQLs / NoSqls / voodoos?
答案 0 :(得分:1)
您存储列表(或更确切地说是树),并且一旦它的一小部分发生变化,就不希望重写整个树。由此我得出结论,结构是巨大的,并且相对经常发生微小的变化。
链接列表都是关于指针追逐的,指针和它们引用的内容很像键和值。您需要有效地存储键值对。项目顺序由链表结构保留。
假设您使用典型的键值存储,从xDBM或Berkeley DB到任何现代NoSQL产品。你也可以采用一个紧凑的SQL引擎,例如sqlite。它们通常使用树来索引键,因此需要O(logN)来访问密钥,或者哈希表需要大约或更少。
您没有指定何时以增量方式保留数据。如果您只是偶尔执行一次(不是每次更新),您需要有效地将数据库与主数据结构进行比较。这将是相对耗时的,因为您需要遍历整个树并查看数据库中的每个节点ID。这是对数但由于必要的I / O而具有巨大的常数。然后你会想要从不再引用的项目中清除持久存储。可能会发生只是将树转储为JSON效率更高。事实上,这就是许多内存数据库所做的事情。
如果您在每次更新主结构时更新持久性结构,那么无论如何都没有必要拥有该主结构。最好用内存键值存储替换它,例如已经具有持久性机制的Redis(以及其他一些好东西)。
答案 1 :(得分:1)
使用关系数据库是可行的解决方案。根据您的需要 - 快速插入,更新,删除 - 我会使用附加列表以及其他自定义项:
id
parent_id
cardinality -- sort order for all nodes with the same parent_id
depth -- distance from the root node
计算cardinality
和depth
可以使用代码完成,也可以 - 最好是 - 用于任何插入,删除或更新的数据库触发器。此外,为了使用一个SELECT语句检索整个层次结构,将调用层次结构桥接表:
id
descendent_id
此表也将通过上述相同的触发器填充,并用作检索给定id
上方或下方的所有节点的方法。
最后,对您列出的选项提供一些补充说明:
<强>更新强>
如果你实现了这个答案的所有部分,添加便宜,重新排序是小成本,移动是昂贵的。权衡是快速层次遍历读取 - 例如在一次操作中找到节点的完整祖先。具体而言,添加叶子是O(1)操作。重新排序意味着更新移动节点之后的所有对等节点的基数。移动意味着更新(1)源和目标对等节点的基数,(2)移动 - 和后代 - 节点深度,以及(3)移除和添加祖先到层次桥接表。
但是,单独使用Adjancency List(即id, parent_id
)并且写入变得便宜,一个级别的读取便宜,但遍历层次结构的读取是昂贵的。后者需要使用递归SQL,如SQL Server和其他RDBMS中的Oracle的CONNECT BY或Common Table Expressions。