因公司业务须要,在表单中每一个字段都会配置自动计算,但自动计算公式中会引用到其余字段中的值。因此但愿能够根据计算公式,优先计算引用的公式。因此最终使用了无回路有向图的扩扑排序来实现。java
直接上代码,后边讲解实现思路。node
/** * 无回路有向图(Directed Acyclic Graph)的拓扑排序 * 该DAG图是经过邻接表实现的。 * * @author lyz */ public class FieldListDG { /** * 邻接表中表对应的链表的顶点 */ private class ENode { int ivex; // 该边所指向的顶点的位置 ENode nextEdge; // 指向下一条弧的指针 } /** * 邻接表中表的顶点 */ private class VNode { String data; // 顶点信息 ENode firstEdge; // 指向第一条依附该顶点的弧 } /** * 顶点数组 */ private List<VNode> mVexs; /** * 建立图(用已提供的矩阵) * <p> * 参数说明: * vexs -- 顶点数组 * edges -- 边数组 */ public FieldListDG(List<String> vexs, List<List<String>> edges) { // 初始化"顶点数"和"边数" int vlen = vexs.size(); int elen = edges.size(); // 初始化"顶点" mVexs = new ArrayList<>(); for (int i = 0; i < vlen; i++) { // 新建VNode VNode vnode = new VNode(); vnode.data = vexs.get(i); vnode.firstEdge = null; // 将vnode添加到数组mVexs中 mVexs.add(vnode); } // 初始化"边" for (int i = 0; i < elen; i++) { // 读取边的起始顶点和结束顶点 int p1 = getPosition(edges.get(i).get(0)); int p2 = getPosition(edges.get(i).get(1)); // 初始化node1 ENode node1 = new ENode(); node1.ivex = p2; // 将node1连接到"p1所在链表的末尾" if (mVexs.get(p1).firstEdge == null) { mVexs.get(p1).firstEdge = node1; } else { linkLast(mVexs.get(p1).firstEdge, node1); } } } /** * 将node节点连接到list的最后 */ private void linkLast(ENode list, ENode node) { ENode p = list; while (p.nextEdge != null) { p = p.nextEdge; } p.nextEdge = node; } /** * 返回String位置 */ private int getPosition(String str) { for (int i = 0; i < mVexs.size(); i++) { if (mVexs.get(i).data.equals(str)) { return i; } } return -1; } /** * 拓扑排序 * <p> * 返回值: * -1 -- 失败(因为内存不足等缘由致使) * 0 -- 成功排序,并输入结果 * 1 -- 失败(该有向图是有环的) */ public List<String> topologicalSort() { int index = 0; int num = mVexs.size(); int[] ins; // 入度数组 String[] tops; // 拓扑排序结果数组,记录每一个节点的排序后的序号。 Queue<Integer> queue; // 辅组队列 ins = new int[num]; tops = new String[num]; queue = new LinkedList<>(); // 统计每一个顶点的入度数 for (int i = 0; i < num; i++) { ENode node = mVexs.get(i).firstEdge; while (node != null) { ins[node.ivex]++; node = node.nextEdge; } } // 将全部入度为0的顶点入队列 for (int i = 0; i < num; i++) { if (ins[i] == 0) { // 入队列 queue.offer(i); } } // 队列非空 while (!queue.isEmpty()) { // 出队列。j是顶点的序号 int j = queue.poll().intValue(); // 将该顶点添加到tops中,tops是排序结果 tops[index++] = mVexs.get(j).data; // 获取以该顶点为起点的出边队列 ENode node = mVexs.get(j).firstEdge; // 将与"node"关联的节点的入度减1; // 若减1以后,该节点的入度为0;则将该节点添加到队列中。 while (node != null) { // 将节点(序号为node.ivex)的入度减1。 ins[node.ivex]--; // 若节点的入度为0,则将其"入队列" if (ins[node.ivex] == 0) { // 入队列 queue.offer(node.ivex); } node = node.nextEdge; } } if (index != num) { return Collections.emptyList(); } List<String> labelList = Arrays.asList(tops); Collections.reverse(labelList); return labelList; } /** * 测试用例 */ public static void main(String[] args) { List<String> vexs = new ArrayList<>(); vexs.add("a"); vexs.add("b"); vexs.add("c"); vexs.add("d"); vexs.add("e"); vexs.add("f"); vexs.add("g"); List<List<String>> edges = new ArrayList<>(); List<String> node = new ArrayList<>(); node.add("a"); node.add("g"); edges.add(node); List<String> node1 = new ArrayList<>(); node1.add("a"); node1.add("c"); edges.add(node1); List<String> node2 = new ArrayList<>(); node2.add("b"); node2.add("a"); edges.add(node2); List<String> node3 = new ArrayList<>(); node3.add("b"); node3.add("d"); edges.add(node3); List<String> node4 = new ArrayList<>(); node4.add("c"); node4.add("f"); edges.add(node4); List<String> node5 = new ArrayList<>(); node5.add("c"); node5.add("g"); edges.add(node5); List<String> node6 = new ArrayList<>(); node6.add("d"); node6.add("e"); edges.add(node6); List<String> node7 = new ArrayList<>(); node7.add("d"); node7.add("f"); edges.add(node7); long start = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { FieldListDG pG = new FieldListDG(vexs, edges); // 拓扑排序 List<String> list = pG.topologicalSort(); } System.out.println("共计时间" + (System.currentTimeMillis() - start)); // list.forEach(e -> System.out.println(e)); } }