一、簡介
tarjan是一種使用深度優先遍歷(DFS)來尋找有向圖強連通份量的一種算法。算法
二、知識準備
棧、有向圖、強連通份量、DFS。數組
三、快速理解tarjan算法的運行機制
提到DFS,能想到的是經過棧來儲存沿途的點,能夠找到全部的環。環自己就是聯通的,因此環對於強連通份量來講環已經很接近最終答案了。要把找環變成找強連通管份量還要考慮:
a.在環外是否是有其餘環在這個強連通份量內(極大性)spa
(會被認爲是2個環).net
b.一些不能構成環的點沒法被考慮到,而他們自己就是強連通份量code
(2不被認爲是一個強連通份量)blog
因此Tarjan算法除了棧還引入了2個數組,分別是:
DFN[N]//節點的時間戳,用來標記節點訪問的前後順序(以及是否被訪問過)
Low[N]//當前「環」裏最早被訪問到的節點,至關於當前這個強連通份量裏的根class
Tarjan的流程是:
DFS,每遇到一個未被訪問過的節點就初始化DFN[i]=Low[i]=index++;
若是找到了環,就在遍歷中用Low數組向上傳遞根的時間戳,直到找到一個點他的時間戳和根的時間戳一致,即DFN[i]=Low[i],這就說明這個點就是根。此時,棧內的全部在根後面的點(包括根)就組成一個強連通份量。遍歷
四、僞代碼im
index=0; tarjan(u) { DFN[u]=low[u]=index++; u入棧; for(遍歷每條邊(u,v)) { if(v未被訪問) { tarjan(v);//DFS low[u]=min(low(u),DFN(v));//將下方的時間戳向上傳遞 } else if(v在棧內) { low[u]=min(low[u],DFN(v));//找到環,比較當前保存的根的時間戳和v的時間戳,取較早的那個做爲根 } if(DFN(u)==low[u]) { //回到了根節點,此時棧內從u日後的節點都是該強連通份量的節點 //找到了強連通份量,逐個退棧,輸出 } } }
五、進一步說明
a.對於問題a,爲何能找到強連通份量內其餘的環?
DFS的問題在於,找到了環當即處理而不考慮其餘環;Tarjan算法把輸出交給根節點處理,在到根節點以前,算法已經遍歷的根節點下的全部節點,天然也把全部環放入了棧。
b.對於問題b,爲何考慮到了不能構成環的那些節點?
對於這些節點,DFN(u)==low[u],至關於他們自己就是強連通份量的根節點。時間戳
六、延伸閱讀若是您仍然有疑問,能夠參考https://blog.csdn.net/qq_34374664/article/details/77488976