簡體   English   中英

Python:有向圖中的所有簡單路徑

[英]Python: all simple paths in a directed graph

我正在使用其中沒有循環的(數量)有向圖,並且我需要找到任何兩個節點之間的所有簡單路徑。 一般來說,我不會擔心執行時間,但我必須在非常多的時間步中為非常多的節點執行此操作 - 我正在處理基於時間的模擬。

我過去曾嘗試過 NetworkX 提供的工具,但總的來說我發現它們比我的方法慢。 不知道最近有沒有什么變化。

我已經實現了這個遞歸函數:

import timeit

def all_simple_paths(adjlist, start, end, path):

    path = path + [start]

    if start == end:
        return [path]

    paths = []

    for child in adjlist[start]:

        if child not in path:

            child_paths = all_simple_paths(adjlist, child, end, path)
            paths.extend(child_paths)

    return paths


fid = open('digraph.txt', 'rt')
adjlist = eval(fid.read().strip())

number = 1000
stmnt  = 'all_simple_paths(adjlist, 166, 180, [])'
setup  = 'from __main__ import all_simple_paths, adjlist'
elapsed = timeit.timeit(stmnt, setup=setup, number=number)/number
print 'Elapsed: %0.2f ms'%(1000*elapsed)

在我的計算機上,每次迭代平均需要 1.5 毫秒。 我知道這是一個小數目,但我不得不這樣做操作很多次。

如果您有興趣,我在這里上傳了一個包含鄰接列表的小文件:

調整列表

我使用鄰接列表作為輸入,來自 NetworkX DiGraph 表示。

任何改進算法的建議(即它是否必須是遞歸的?)或我可以嘗試的其他方法都非常受歡迎。

謝謝你。

安德烈亞。

通過在此處緩存共享子問題的結果,您可以在不更改算法邏輯的情況下節省時間。

例如, all_simple_paths(adjlist, 'A', 'D', [])調用all_simple_paths(adjlist, 'A', 'D', [])all_simple_paths(adjlist, 'D', 'E', [])計算all_simple_paths(adjlist, 'D', 'E', []) 在此處輸入圖片說明

Python 有一個用於此任務的內置裝飾器lru_cache 它使用哈希來記住參數,因此您需要更改adjListtuple path ,因為list不可哈希。

import timeit
import functools

@functools.lru_cache()
def all_simple_paths(adjlist, start, end, path):

    path = path + (start,)

    if start == end:
        return [path]

    paths = []

    for child in adjlist[start]:

        if child not in path:

            child_paths = all_simple_paths(tuple(adjlist), child, end, path)
            paths.extend(child_paths)

    return paths


fid = open('digraph.txt', 'rt')
adjlist = eval(fid.read().strip())

# you can also change your data format in txt
adjlist = tuple(tuple(pair)for pair in adjlist)

number = 1000
stmnt  = 'all_simple_paths(adjlist, 166, 180, ())'
setup  = 'from __main__ import all_simple_paths, adjlist'
elapsed = timeit.timeit(stmnt, setup=setup, number=number)/number
print('Elapsed: %0.2f ms'%(1000*elapsed))

在我的機器上運行時間:
- 原始:0.86ms
- 帶緩存:0.01ms

而且這種方法應該只在有很多共享的子問題時才有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM