这是我正在进行的个人项目之一。我有一个N个节点的DAG(比如百万),我将查询两个节点的连接[isConnected(a,b}]。我将在线查询DAG(比如百万次)。是否有办法优化过程
以下是我能提出的最佳方法。
BFS = O(M * N)
Dijkstra = O(M * E * log N)其中E是图中边的数量。
这个过程还有其他更好的方法吗?我现在正在使用第二种策略。这需要我的系统永远。
答案 0 :(得分:1)
我可以看到一些加速,但我总体上无法有效地解决问题。
首先,将图表视为无向图并将其拆分为连接组件。必须断开不在同一个连接组件中的两个点。
对于每个连接的组件,再次将其视为有向图并将其拆分为强连接组件。必须连接同一个强连接组件中的两个点。
现在将每个连接的组件视为节点的DAG,其中每个节点实际上是一个强连接的组件。你可以拓扑排序这个。如果节点A在节点B的上游,则没有路径阻止从B到A的流。
您的DAG可能不是树,但如果是,您可以有效地解决最常见的祖先问题。从A到B的唯一路径上升到其最低共同祖先并再次返回。如果这两条路线都在朝向拓扑排序的正确方向,那么您可以从A到B。
对于完全不同的方法,谷歌搜索将找到许多算法,用于大型网络中的快速最短路径。其中一些可能适用。
答案 1 :(得分:1)
优化流程的方法是生成一些辅助结构,以加快可达性查询。即使不考虑生成这种结构(或更新它们)的时间,辅助结构的大小和查询的速度之间也存在平衡。
在Reachability Queries in Very Large Graphs: A Fast Refined Online Search Approach论文的引言中对此进行了很好的描述;提出的方法是每个顶点使用两个额外的数字。您可以找到其他解决方案的参考资料。
答案 2 :(得分:0)
根据图表的大小,可能会使用完整的方法来查看一些大数据方法。也就是说,如果您的图表大到几千兆字节,则内存/磁盘访问将成为瓶颈,而不是CPU操作。
解决此类问题需要您以某种方式对数据进行分组,以便只需加载一次数据。因此,您应该使您的数据结构可以分成适合内存的块,并且可以一次性处理,以后不需要进一步处理。
针对您的问题的一个这样的大数据方法是在连接的子图中划分图形,并且仅在这些子图上运行Dijkstra。然后,您可以简单地检查每个子图是否实际连接了入口点和输出点(因为您有一个DAG)再次使用Dijkstra。但是,这需要您预处理数据(一次),并且您的数据结构应该是子图是彼此靠近的内存块。
答案 3 :(得分:0)
您可以计算DAG的transitive closure,然后在固定时间内回答查询。但是,这需要高达O(n³)的时间和O(n²)存储器。有些方法可以接受更长的查询时间,以便更快地进行预处理或降低内存使用量,请参阅例如this presentation