假设您有一个存储有序树层次结构的平面表:
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
Run Code Online (Sandbox Code Playgroud)
这是我们所拥有的图表[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个子节点.不过,我并没有考虑到"数百万条目".
不要将我选择的节点命名('Node 1.1.1')误认为是依赖的东西.节点同样可以称为"Frank"或"Bob",不暗示命名结构,这只是为了使其可读. …
您在数据库中建模和检索分层信息的方式有哪些?
我知道有两种方法:邻接列表和嵌套树.据说由于大量查询,邻接列表在遍历上使用会很慢.但我不知道这方面的任何实际数字.我正在制作的网站将有200页.遍历生成(例如)站点地图需要花费超过0.3秒的时间吗?
使用LAMP堆栈在MySQL(innoDB)上运行.
如果可能的话,我更愿意实现邻接,因为设计更简单.
谢谢.
我正在使用的DBMS是MySQL,编程环境是Delphi 7(这个例子并不重要).
我有一个名为'subject'的表格,我将所有书籍主题存储在系统中.受试者可以有亲子关系,比如科学可以分为数学和物理,而数学可以细分为微积分,代数,几何和我们去.
我想要的是创建一个填充了该表中日期的树.拜托,帮帮我吧.它甚至与您用于说明目的的语言无关,它只是伪代码.
Subject表的数据库图如下所示:

Subject表定义:
DROP TABLE IF EXISTS subject;
CREATE TABLE IF NOT EXISTS subject ( # Comment
subject_id INT UNSIGNED NOT NULL AUTO_INCREMENT, # Subject ID
subject VARCHAR(25) NOT NULL, # Subject name
parent_id INT UNSIGNED NULL DEFAULT NULL, # Parent ID as seen from
PRIMARY KEY (subject_id), # the diagram refers to
UNIQUE (subject), # the subject_id field
INDEX (parent_id),
CONSTRAINT fk_subject_parent
FOREIGN KEY (parent_id)
REFERENCES subject (subject_id)
ON DELETE RESTRICT
ON UPDATE CASCADE
) ENGINE=InnoDB …Run Code Online (Sandbox Code Playgroud) 我想每个曾经使用过Delphi的VirtualStringTree的人都会同意它是一个很棒的控件.它是一个"虚拟"控件(您的数据必须保存在其他位置)所以我在想什么数据结构最适合这样的任务?IMO数据结构必须支持层次结构,它必须快速且易于扩展.最简单的实现是使用记录,这就是可以找到的大多数文档所暗示的内容.但是如果你需要做一些快速查找,计算总数等怎么办?您与VirtualStringTree一起使用的数据结构是什么?
编辑1:我正在使用Delphi 2010.
好的,我会尝试提供一些有关我的要求的更多细节.数据大小可以变化很大,从1到数千个项目.每个项目可以包含多个字符串,整数值.我需要随机访问,我的数据可以在应用程序生命周期中多次更改.良好的性能是非常理想的.我还需要数据保存和重新加载.
EDIT2:得到1个答案,所以我会试着评论我的意见.谢谢,Dorin的答案,但我不认为你的结构很方便.1)它不处理层次结构.2)为每个节点分别设置TStringList或TList不是非常有效的IMO.通过这种实现,我只能查找当前节点的数据,但不能有效地搜索整个树.
我认为这个数据结构必须像一棵树.它必须具有能够添加子节点的节点.然后我就可以在OnInitNode事件中获取节点的数据,检查我的节点是否有一些子节点,如果是,则设置ivsHasChildren标志,然后在OnInitChildren事件中设置正确的子节点数.稍后在OnGetText事件中,我可以从我的节点结构中获取所需的数据,并根据Column索引将其设置为CellText.我的想法是拥有一个单独的数据结构,并使用它完成所有需要的操作,而无需使用VirtualStringTree.希望有人得到我的观点:).
EDIT3:我发现了非常有趣的JclTrees单元,乍一看可以用来实现我正在寻找的东西.它属于JCL library.缺乏体面的文档使得很难快速调查它的功能.当我有更多时间时,我可能会更深入地研究它.
我需要一个可以与Virtual Treeview一起使用的树实现,它不会消耗太多内存,易于使用,并且与VT一样快(也就是说,当我将数据存储在VT本身时)
我尝试过Linas的svTree - 它易于使用,但不如我希望的那么快和内存友好.
此外,只想指出我的应用程序将管理数千个节点.:)
你推荐什么免费图书馆?您是否能够构建一个如何在Virtual Treeview中使用它的最小演示?
我正在寻找一个非可视持久树(TStringTree)实现.如果有人知道任何好的实施,请告诉我.
谢谢.
我的应用程序将通过虚拟节点循环并检查其数据.我使用另一个表单来执行此操作比包含VirtualStringTree的表单.(我得到了我的理由;))
我的问题是:我如何将这些节点+他们的数据传递给我的其他形式的函数,然后能够循环通过节点(我知道如何循环,我只需要以我的其他形式提供节点) ).
此外,请注意,一旦显示Processing表单,就会销毁包含VirtualStringTree的表单!
我怎么能这样做?我正在考虑创建一个动态的VirtualStringTree,并以某种方式将节点从一棵树传递到另一棵树,但我会先问这里是否有更好的解决方案.:)
谢谢,杰夫.