【发布时间】:2021-06-29 09:29:48
【问题描述】:
对有向图的节点进行排序的最佳方法是什么?我已经用数组 B 的数组 A 制作了一个算法,其中数组 A 的元素代表列,数组 B 中元素的位置代表行。然后根据数组 A 和数组 B 中的位置将节点放置在网格中(例如,如果节点位于数组 B 中,该节点位于数组 A 的位置 2 和数组 B 的位置 3 中,那么它将被排序第 2 列和第 3 行并在那里渲染)。如果删除先前找到的根节点,则根据它们是否为根节点来确定列。
由于行的排序是随机的,您可以想象该图看起来并不太理想和有序。
图本身没有循环,基本上是一棵树,不同的是,一个子节点可以有多个父节点。
我和我的队友正在努力寻找一种对行进行最佳排序的方法,因此图表看起来最有序。 我们试图找到一个库,它可能只是以一种很好的方式对我们的节点进行排序,但到目前为止我们没有找到任何东西,这就是为什么我们现在尝试自己寻找解决方案。
第一个想法是,我们根据父节点的行来决定行。但是在边缘情况下它会变得相当复杂,在这种情况下,父节点和子节点之间存在大量连接,父节点有多个子节点,而子节点有多个父节点。
我们的代码只是获取一个节点和边的数组。然后根据它们的父节点和它们在树中的层次结构将它们分类到列中。
现在我们需要对它们进行垂直排序,尽可能让边缘不重叠。
nodeData.test.js
it('gets root node array and puts it in a grouped array, simpler test', () => {
expect(
getSortedNodes(
// nodes:
[{ id: 1 }, { id: 2 }, { id: 3 }],
// edges:
[
{ target: 3, source: 2 },
{ target: 3, source: 1 },
]
)
).toStrictEqual([[{ id: 1 }, { id: 2 }], [{ id: 3 }]]) // resulting matrix
})
nodeData.js
//parameters when called: accumulated is an empty array, rootIds needs to be
//arrays of root Ids (which need to be extracted from nodes before calling function)
//edges is an array of edges, which contain source and target IDs
//thus this function is private and should only be called in getSortedNodes()
function sortNodes(accumulated, nodes, nodeIds, edges) {
if (!nodeIds.length) {
return accumulated
}
const targetList = edges.map(({ target }) => target)
const rootIdLayer = difference(nodeIds, targetList, true)
const rootNodes = nodes.filter(node => rootIdLayer.includes(node.id))
const accumulatedList = [...accumulated]
accumulatedList.push(rootNodes)
const remainingNodeIds = difference(nodeIds, rootIdLayer, true)
const remainingEdges = edges.filter(edge => !rootIdLayer.includes(edge.source))
return sortNodes(accumulatedList, nodes, remainingNodeIds, remainingEdges)
}
// parameters take arrays or nodes and edges
// gives out sorted Array of nodes, which can be used to position those in a grid
export function getSortedNodes(nodes, edges) {
const nodeIds = nodes.map(({ id }) => id)
return sortNodes([], nodes, nodeIds, edges)
}
我们打算使用一个子节点更靠近其父节点的矩阵,而不是随机对齐的矩阵(请参阅单元测试)。
这里有一些伪代码来说明。 3 是 2 的孩子,4 是 3 的孩子。
nodes:
[1,2,3,4]
edges:
[
{source: 2, target: 3},
{source: 3, target: 4}
]
expected result:
[
[1, 2],
[null, 3],
[null, 4]
]
当前,丑陋的图表:
父母在孩子旁边的预期图表:
当边缘交叉时,这会变得更加复杂。
更新:我们决定尝试Sugiyama method。一旦我们有结果,我们将提供更新。此外,如果我们成功了,我们会提供答案。
如果您有任何我们可以尝试的建议或库,请随时发表评论或回答!
【问题讨论】:
-
对不起,我很难理解你的问题。我建议您提供一些数据结构以及您想要实现的排序的不同示例。
-
为了说明目的在底部添加了一些伪代码。现在好点了吗?
-
更好。但我仍然不明白得到预期结果的逻辑是什么。预期结果是什么意思?
-
有很多库可以计算带有大量花里胡哨配置的图形布局...您是否考虑过使用布局库(也可以选择使用它们进行渲染)?
-
我现在明白了。但是,
child nodes closer to their parents.的定义并不明确。假设一个父节点可以链接到 3 个子节点,你如何定义哪个子节点应该更靠近父节点?
标签: javascript arrays sorting matrix graph