求圖的連通子圖 python 使用 networkx (BFS, DFS)

本來這個問題應(yīng)該是放在并查集里面一起說明凹蜈,不過并查集篇幅比較大,就單獨把這個問題拿出來了忍啸。

并查集的問題也可以轉(zhuǎn)化為圖的連通子圖問題仰坦。給一個圖G,返回它的所有不連通的子圖计雌。

1. 使用networkx包求圖的所有不連通的子圖

主要使用connected_components()方法缎岗。下面是一個例子。

import networkx as nx
import matplotlib.pyplot as plt

pointList = ['A','B','C','D','E','F','G']
linkList = [('A','B'),('B','C'),('C','D'),('E','F'),('F','G'),]


def subgraph():
    G = nx.Graph()
    # 轉(zhuǎn)化為圖結(jié)構(gòu)
    for node in pointList:
        G.add_node(node)

    for link in linkList:
        G.add_edge(link[0], link[1])

   # 畫圖
    plt.subplot(211)
    nx.draw_networkx(G, with_labels=True)
    color =['y','g']
    subplot = [223,224]
    # 打印連通子圖
    for c in nx.connected_components(G):
       # 得到不連通的子集
        nodeSet = G.subgraph(c).nodes()
       # 繪制子圖
        subgraph = G.subgraph(c)
        plt.subplot(subplot[0])  # 第二整行
        nx.draw_networkx(subgraph, with_labels=True,node_color=color[0])
        color.pop(0)
        subplot.pop(0)

    plt.show()
subgraph()

原圖與分開后的子圖


Screen Shot 2019-04-24 at 9.57.27 AM.png

那么networkx的connected_components()方法是如何實現(xiàn)的呢白粉,也很簡單传泊,通過BFS遍歷來找連通的子圖。進(jìn)行一次完整的BFS遍歷可以一組連通節(jié)點鸭巴,放入一個集合眷细,然后從沒有遍歷到的節(jié)點再開始一次BFS遍歷,放入集合就是另一組連通子圖鹃祖,以此類推可以幾次BFS就找到幾個連通子圖溪椎,看源碼:

seen = set()
    for v in G:
        if v not in seen:
            c = set(_plain_bfs(G, v))
            yield c
            seen.update(c)

2. 一個很經(jīng)典的廣度優(yōu)先算法

networkx實現(xiàn)的BFS算法,這里使用G_adj[v]是鄰接矩陣的存儲方式恬口,所以時間復(fù)雜度是O(|V|^2)

def _plain_bfs(G, source):
    """A fast BFS node generator"""
    G_adj = G.adj
    seen = set()
    nextlevel = {source}
    while nextlevel:
        thislevel = nextlevel
        nextlevel = set()
        for v in thislevel:
            if v not in seen:
                yield v
                seen.add(v)
                nextlevel.update(G_adj[v])

鄰接表形式存儲時校读,每個頂點均需搜索一次,時間復(fù)雜度T1=O(v)祖能,從一個頂點開始搜索時歉秫,開始搜索,訪問未被訪問過的節(jié)點养铸。最壞的情況下雁芙,每個頂點至少訪問一次,每條邊至少訪問1次钞螟,這是因為在搜索的過程中兔甘,若某結(jié)點向下搜索時,其子結(jié)點都訪問過了鳞滨,這時候就會回退洞焙,故時間復(fù) 雜度為O(E),算法總的時間復(fù) 度為O(|V|+|E|)
時間復(fù)雜度參考鏈接(https://blog.csdn.net/Charles_ke/article/details/82497543 )

3. 在這里順便回顧一下深度優(yōu)先遍歷(DFS)

鄰接矩陣表示時,查找每個頂點的鄰接點所需時間為O(|V|)澡匪,要查找整個矩陣熔任,故總的時間復(fù)雜度為O(|V|^2)
鄰接表表示時,查找所有頂點的鄰接點所需時間為O(E)仙蛉,訪問頂點的鄰接點所花時間為O(V),此時笋敞,總的時間復(fù)雜度為O(V+E) (這里沒自己實現(xiàn)鄰接表代碼碱蒙,直接抄書上的過來了)

G的定義與上面相同
遞歸形式(參考王道數(shù)據(jù)結(jié)構(gòu)):

G_adj = G.adj
seen = set()
def DFSTraverse(G):
    for v in G:
        if v not in seen:
            c = set(DFS(G,v))
            seen.update(c)

def DFS(G,v):
    seen.add(v)
    yield v
    # 訪問操作
    print(v)
    for w in G_adj[v]:
        if w not in seen:
            DFS(G,w)

DFSTraverse(G)

使用隊列實現(xiàn)DFS(參考鏈接https://blog.csdn.net/changyuanchn/article/details/79008760
):


def DFS2(G,node0):
    G_adj = G.adj
    #queue本質(zhì)上是堆棧荠瘪,用來存放需要進(jìn)行遍歷的數(shù)據(jù)
    #order里面存放的是具體的訪問路徑
    queue,order=[],[]
    #首先將初始遍歷的節(jié)點放到queue中,表示將要從這個點開始遍歷
    queue.append(node0)
    while queue:
        #從queue中pop出點v赛惩,然后從v點開始遍歷了哀墓,所以可以將這個點pop出,然后將其放入order中
        #這里才是最有用的地方喷兼,pop()表示彈出棧頂篮绰,由于下面的for循環(huán)不斷的訪問子節(jié)點,并將子節(jié)點壓入堆棧季惯,
        #也就保證了每次的棧頂彈出的順序是下面的節(jié)點
        v = queue.pop()
        order.append(v)
        #這里開始遍歷v的子節(jié)點
        for w in G_adj[v]:
            #w既不屬于queue也不屬于order吠各,意味著這個點沒被訪問過,所以講起放到queue中勉抓,然后后續(xù)進(jìn)行訪問
            if w not in order and w not in queue:
                queue.append(w)
    return order

def DFSTraverse2(G):
    seenArray = []
    for v in G:
        if v not in seenArray:
            order = DFS2(G,v)
            seenArray.extend(order)
    return seenArray

seenArray = DFSTraverse2(G)
print(seenArray)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贾漏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子藕筋,更是在濱河造成了極大的恐慌纵散,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隐圾,死亡現(xiàn)場離奇詭異伍掀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)暇藏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門蜜笤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盐碱,你說我怎么就攤上這事瘩例。” “怎么了甸各?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵垛贤,是天一觀的道長。 經(jīng)常有香客問我趣倾,道長聘惦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮善绎,結(jié)果婚禮上黔漂,老公的妹妹穿的比我還像新娘。我一直安慰自己禀酱,他們只是感情好炬守,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著剂跟,像睡著了一般减途。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上曹洽,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天鳍置,我揣著相機(jī)與錄音,去河邊找鬼送淆。 笑死税产,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的偷崩。 我是一名探鬼主播辟拷,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼阐斜!你這毒婦竟也來了衫冻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤智听,失蹤者是張志新(化名)和其女友劉穎羽杰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體到推,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡考赛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莉测。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颜骤。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖捣卤,靈堂內(nèi)的尸體忽然破棺而出忍抽,到底是詐尸還是另有隱情,我是刑警寧澤董朝,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布鸠项,位于F島的核電站,受9級特大地震影響子姜,放射性物質(zhì)發(fā)生泄漏祟绊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牧抽。 院中可真熱鬧嘉熊,春花似錦、人聲如沸扬舒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讲坎。三九已至孕惜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衣赶,已是汗流浹背诊赊。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工厚满, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留府瞄,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓碘箍,卻偏偏與公主長得像遵馆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子丰榴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. 圖的定義和基本術(shù)語 線性結(jié)構(gòu)中货邓,元素僅有線性關(guān)系,每個元素只有一個直接前驅(qū)和直接后繼四濒;樹形結(jié)構(gòu)中换况,數(shù)據(jù)元素(...
    yinxmm閱讀 5,457評論 0 3
  • 圖是由頂點的有窮非空集合和頂點之間的邊的集合組成,通常表示為:G(V盗蟆,E)戈二,其中,G表示一個圖喳资,V是圖中的頂點的集...
    keeeeeenon閱讀 548評論 0 2
  • 1)這本書為什么值得看: Python語言描述觉吭,如果學(xué)的Python用這本書學(xué)數(shù)據(jù)結(jié)構(gòu)更合適 2016年出版,內(nèi)容...
    孫懷闊閱讀 12,484評論 0 15
  • 很早就聽過這部電影仆邓,在看了《聲之形》后還是擋不住好奇心來看了鲜滩。唯美的畫風(fēng),動人的音樂节值,無邏輯漏洞的緊湊情節(jié)都促使我...
    西顧west閱讀 214評論 0 1
  • 又是一年畢業(yè)季搞疗。今天嗓蘑,我們來聊聊年輕人的話題。 之前我們說過90后為什么這么窮,也說過為什么現(xiàn)在的年輕人很多都是月...
    Albert周閱讀 198評論 0 0