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

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

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中是否存在从根本上更好的方法来存储这样的树结构? nosql


编辑和添加 工具

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

我所说的“结果集”能够图片为一个哈希表数组(保留在该术语中)。 对于个人示例,本应已经存在。 一些答案须要付出额外的努力,而后再进行构建,但这不要紧。 code

这棵树能够任意深。 每一个节点能够有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路线。

相关文章
相关标签/搜索