数据结构和算法在流程画布中的实际应用

图灵奖的获得者,Pascal 之父——Niklaus Wirth ,有个经典说法:“算法+数据结构=程序”(Algorithm+Data Structures=Programs)。我们以这个说法为思路,看在流程画布这个场景中,如何应用数据结构和算法来解决实际的业务需求。

树和图

在数据结构中,对树的描述为:树是n(n≥0)个结点的有限集,它或为空树(n=0);或为非空树,对于非空树T:

  1. 有且仅有一个称之为根的结点;

  2. 除根结点以外的其余结点可分为m(m>0)个互不相交的有限集T1, T2, …, Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。

由上述描述可以看出,树的结构定义是一个递归的定义,即在树的定义中又用到树的定义,它道出了树的固有特性。树常用的存储结构有:顺序存储、链式存储。

对图的描述为:图G由两个集合V和E组成,记为G=(V, E),其中V是顶点的有穷非空集合,E是V中顶点偶对的有穷集合。V(G)为图的顶点集合,不可以为空;E(G)为图的边集合,可以为空。如果边集E(G)为有向边的集合,则称图为有向图;如果边集E(G)为无向边的集合,则称图为无向图。

图常用的存储结构有:邻接矩阵、邻接表、十字链表、邻接多重表。

树和图是画布这个场景中关联度最高的两种数据结构(当然,最基础的还是链表结构)。

G6

G6 是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画等图可视化的基础能力,借助 G6 的能力,我们可以快速搭建自己的图分析或图编辑应用。流程画布底层便使用了 antv/g6 来实现图可视化的功能。

根据对其功能使用程度的不同,我们梳理 G6 的核心概念如下:

G6中对图 Graph 接收的参数定义如下:

export interface GraphData {
    nodes?: NodeConfig[];
    edges?: EdgeConfig[];
    combos?: ComboConfig[];
    [key: string]: any;
}

官网给出的最简单的快速开始的 demo 代码片段如下:

const data = {
  nodes: [
    {
      id: 'node1',
      x: 100,
      y: 200,
    },
    {
      id: 'node2',
      x: 300,
      y: 200,
    },
  ],
  edges: [
    {
      source: 'node1',
      target: 'node2',
    },
  ],
};
 
const graph = new G6.Graph({
  container: 'mountNode',
  width: 800,
  height: 500,
});
graph.data(data);
graph.render();

由上面两段代码可以看出,nodes 和 edges 是对图结构中顶点集合和边集合的数据表示,同时通过 combos 字段实现了顶点分组的能力。看到此处,我们可以得出结论:真正的元素绘制部分其实无需关心,我们要做的更多是对顶点集和边集数据的管理。

顶点项中的 x、y 字段是可选的,当数据中没有节点位置信息,或者数据中的位置信息不满足需求时,需要借助一些布局算法对图进行布局。

由G6的核心概念可以看到,框架本身已经实现了多种经典布局算法,其中不乏以树图为主的脑图布局,但根据需求描述中对UI设计和交互的定义,现有布局算法无法满足我们的需求。因此我们不仅要实现自定义顶点、边,还要实时计算每个顶点的坐标值来实现自定义布局的逻辑。

G6 在提供更高的灵活性的同时,也因处理数据带来了不可避免的复杂性,节点的坐标值计算和节点管理(新增、删除)便是其中的典型场景。

数据结构定义

G6 本身是对图可视化的实现,但流程画布这个场景中,我们在真正的实现中采用了链式存储的树结构。

实际开发过程中,对节点的数据类型定义如下:

interface IWorkflowNode<T extends WorkflowNodeParamsXOR> {
  id: string;
  type: TWorkflowNodeType;
  params: T;
  parent: string[];
  children: string[];
}
说明:
  • parent 为父节点引用(以 id 形式存储)

  • children 为子节点引用(以 id 形式存储)

满足二叉数的双向链表结构

算法

我们需要对数据进行处理的点主要有两个:

  1. 节点坐标计算

  2. 节点删除时,对当前节点、关联边和子树的删除

基于上述的数据结构定义,实现上述两点功能均用到同一个算法:二叉树的深度优先、前序遍历算法(采用递归解法)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值