将平板餐桌解析成树的最有效/最优雅的方法是什么?

让人想犯罪 __ 提交于 2020-02-27 07:19:17

假设您有一个存储有序树层次结构的平面表:

Id   Name         ParentId   Order
 1   'Node 1'            0      10
 2   'Node 1.1'          1      10
 3   'Node 2'            0      20
 4   'Node 1.1.1'        2      10
 5   'Node 2.1'          3      10
 6   'Node 1.2'          1      20

这是一个图,我们有[id] Name 。 根节点0是虚构的。

[0] ROOT
                          /    \ 
              [1] Node 1          [3] Node 2
              /       \                   \
    [2] Node 1.1     [6] Node 1.2      [5] Node 2.1
          /          
 [4] Node 1.1.1

您将使用哪种简约方法将其作为正确排序,正确缩进的树输出到HTML(就此而言,还是文本)?

进一步假设您只有基本的数据结构(数组和哈希图),没有带有父/子引用的奇特对象,没有ORM,没有框架,只有两只手。 该表表示为结果集,可以随机访问。

可以使用伪代码或简单的英语,这纯粹是一个概念性问题。

额外的问题:在RDBMS中是否存在从根本上更好的方法来存储这样的树结构?


编辑和添加

要回答一个评论者( Mark Bessey )的问题:根节点不是必需的,因为它永远不会显示。 ParentId = 0是表示“这些是顶级”的约定。 Order列定义如何对具有相同父代的节点进行排序。

我所说的“结果集”可以图片为一个哈希表数组(保留在该术语中)。 对于我的示例,本应已经存在。 一些答案需要付出额外的努力,然后再进行构建,但这没关系。

这棵树可以任意深。 每个节点可以有N个子节点。 不过,我并没有真正想到“成千上万的条目”树。

不要将我对节点命名(“节点1.1.1”)的选择误认为是要依赖的东西。 这些节点也可以称为“ Frank”或“ Bob”,没有暗示命名结构,这仅仅是为了使其可读。

我已经发布了自己的解决方案,因此你们可以将它分解成碎片。


#1楼

考虑将noeo工具(例如neo4j)用于层次结构。 例如,诸如linkedin之类的联网应用程序使用couchbase(另一个nosql解决方案)

但是,仅将nosql用于数据集市级别的查询,而不用于存储/维护事务


#2楼

假设您知道根元素为零,这是要输出到文本的伪代码:

function PrintLevel (int curr, int level)
    //print the indents
    for (i=1; i<=level; i++)
        print a tab
    print curr \n;
    for each child in the table with a parent of curr
        PrintLevel (child, level+1)


for each elementID where the parentid is zero
    PrintLevel(elementID, 0)

#3楼

如果可以创建嵌套的哈希图或数组,那么我可以简单地从表头开始将表格添加到嵌套数组中。 我必须跟踪每行到根节点,以便知道要插入嵌套数组中的哪个级别。 我可以使用记忆,这样我就不需要一遍又一遍地查找同一个父母。

编辑:我将首先将整个表读入数组,因此不会重复查询数据库。 当然,如果您的桌子很大,这将不切实际。

构建完结构后,我必须先遍历深度并打印出HTML。

没有更好的基本方法来使用一个表存储此信息(尽管我可能错了;),并且希望看到一种更好的解决方案)。 但是,如果您创建一个方案来使用动态创建的db表,那么您将在牺牲简单性和SQL地狱的风险的同时开辟了一个全新的世界;)。


#4楼

您可以使用哈希图模拟任何其他数据结构,因此这不是一个可怕的限制。 从顶部到底部扫描,您将为数据库的每一行创建一个哈希图,并为每一列创建一个条目。 将每个哈希表添加到键入ID的“主”哈希表。 如果任何节点具有尚未出现的“父”节点,请在主哈希图中为其创建一个占位符条目,并在看到实际节点时将其填充。

要打印出来,请对数据进行简单的深度优先传递,并始终跟踪缩进级别。 通过为每一行保留一个“子项”条目,并在扫描数据时填充它,可以使此过程变得更加容易。

至于是否有一种“更好”的方式将树存储在数据库中,这取决于您如何使用数据。 我已经看到了具有已知最大深度的系统,该系统为层次结构中的每个级别使用了不同的表。 如果树中的级别毕竟不完全相等(顶层类别与叶子不同),这很有道理。


#5楼

好的选择,我会使用对象。 我会为每个记录创建一个对象,其中每个对象都有一个children对象集合,并将它们全部存储在ID为键的assoc数组(/ hashtable)中。 并快速浏览该收藏集,将子级添加到相关的子级字段中。 简单。

但是由于限制某些良好的OOP的使用对您很无聊,因此我可能会根据以下条件进行迭代:

function PrintLine(int pID, int level)
    foreach record where ParentID == pID
        print level*tabs + record-data
        PrintLine(record.ID, level + 1)

PrintLine(0, 0)

编辑:这类似于其他几个条目,但我认为它稍微干净一些。 我要添加的一件事:这是非常消耗SQL的。 真讨厌 如果可以选择,请执行OOP路线。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!