拓扑排序在处理树形关系结构中的应用

文章讲述了如何利用拓扑排序算法解决在MySQL中存储树形结构数据的问题,特别是针对具有层级关系的部门表。通过深度优先遍历和处理入度为0的节点,实现了将所有部门的完整隶属关系整合成列表。同时,讨论了算法的性能和可能的优化策略,包括数据预处理和增加入度列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Preface


偶然在QQ上的一个交流群中看到了一位群友的棘手需求。互联网开发中,数据的落盘存储通常在MySQL中。MySQL是一种关系型数据库,以“行”为基本的存储单元,然后通过外键等建立数据实体模型之间的联系。

但有些数据的存储,在MySQL上并没有那么友好。比如一个存在等级与隶属关系的部门表。每个部门会有一个所直接隶属的上级部门,一个部门又可能会有多个直属的下级部门。在MySQL中存储时,每一个部门都要有一个parent列,来指明自己的直属上级部门。这样一来,就会得到一张实际为树形关系的部门结构表。

实体数据之间的关系,是一张树形结构图

话题回到群友的需求上来,群友的需求也很简单,通过数据库查询与业务层的处理,将所有部门的完整隶属关系整合成一个列表,如下所示:

0: 北京分公司 -> 人事部 -> 档案组
1: 北京分公司 -> 人事部 -> 绩效组
2: 北京分公司 -> 科技部 -> 前台组
             ...

处理思路


看到了这样的需求后,第一个闪念在脑海中的想法是——拓扑排序。我们知道树结构是图结构的一种特例,树结构是一种无环图,因此只要数据库记录层面不出问题,将查询得到的数据按照树结构组织起来,那么该结构的拓扑序列是一定存在的。

在实际拓扑排序中,只要将每条数据的parent域作为一条指向其他结点的边来看待即可。从入度为零的结点出发,按照parent指针进行深度优先遍历,将路径上的结点收集起来,即可完成上述需求。

如果想要了解拓扑排序的过程或者算法原理,可以查看数据结构书籍中关于章节的讲述,也可查看下面链接中的解释。

拓扑排序百度百科:https://baike.baidu.com/item/%E6%8B%93%E6%89%91%E6%8E%92%E5%BA%8F

拓扑排序维基百科:https://zh.wikipedia.org/wiki/%E6%8B%93%E6%92%B2%E6%8E%92%E5%BA%8F

设计与实现


算法性能预估

在拓扑排序之前,我们需要考虑一下算法的性能问题。首先拓扑排序的时间复杂度在 O ( N 2 ) O(N^2) O(N2),因此理论上该算法的性能并不好。但是时间复杂度只是一个理论指标,实际我们还需要考虑问题的规模。通常部门的架构表的数据量不会很大,对于某些场景下,该表的数据量也就在几千到几万条之间。

同时,部门架构表经常面对的是读多写少的场景,因此一定程度上,我们可以将一次业务处理的数据进行缓存。而且在业务处理中,面对如此小量的数据,通常我们可以从磁盘中一次性将其读入到内存,然后供业务层处理,这样可以减少磁盘IO的次数。

算法实现

准备承载数据库查询结果的POJO类

@Data  
@NoArgsConstructor  
@AllArgsConstructor  
static class Node {
     
    private Integer id;            // 部门ID  
    private String name;           // 部门名称  
    private Integer parent;        // 上级部门的ID  
    private Integer inDegree = 0;  // 该部门的入度(该部门子部门的数量)  
}

模拟数据库查询得到整张部门表数据

final List<Node> dbQuerySet = Arrays.asList(  
        new Node(1, "北京分公司", null, 0),  
        new Node(2, "人事部", 1, 0),  
        new Node(3, "科技部", 1, 0),  
        new Node
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值