llvm中的Tarjan強連通分量演算法

2021-09-13 11:28:28 字數 2126 閱讀 3744

llvm中的強連通演算法使用的也是tarjan演算法,與我自己實現的那種粗糙的演算法不同,llvm使用棧代替遞迴實現dfs,一方面防止執行棧空間不足的問題,另一方面借助這個棧,可以記住當前遍歷的狀態,從而實現了強連通分量上的迭代器。總之實現的十分的優雅。

**檔案在include\llvm\adt\scciterator.h中。

現在我們來看一下具體實現。

首先定義了兩個靜態成員函式begin和end,就是類似容器裡對應的頭和尾。

static scc_iterator begin

(const grapht &g)

static scc_iterator end

(const grapht &

)

這裡其實就是呼叫了個scc_iterator的建構函式,grapht是對圖的操作抽象出來的乙個trait類。

scc_iterator

(noderef entryn)

:visitnum(0

)

dfsvisitone用於處理當前正在訪問的節點,在遞迴的tarjanscc演算法中,訪問乙個節點的操作是更新dfs序,並壓入棧中,這裡也是一樣的。不同之處就是增加了個棧來記錄dfs當前的狀態。

template 

void scc_iterator::

dfsvisitone

(noderef n)

llvm使用visitstack來記錄當前的迭代狀態,用於代替執行棧。

getnextscc獲取了第乙個scc,實際上相當於遞迴版的tarjanscc演算法中遇到第乙個強連通分量後就暫停程式。

template 

void scc_iterator::

getnextscc()

while

(currentscc.

back()

!= visitingn)

;return;}

}

在getnextscc一開始的地方,就會迭代遍歷所有子結點,這裡執行的操作其實和遞迴版是一樣的,如果沒有訪問過,則繼續向下遍歷,否則和子節點的最小dfs序去比較,如果子節點較小,則更新到這個較小的dfs序:

template 

void scc_iterator::

dfsvisitchildren()

// 如果子節點dfs序小於記錄中的最小dfs序,則更新最小dfs序

unsigned childnum = visited->second;

if(visitstack.

back()

.minvisited > childnum)

visitstack.

back()

.minvisited = childnum;

}}

演算法**現了兩個棧,其中sccnodestack對應的就是tarjan演算法中的棧,用於記錄當前scc中的所有節點,而visitstack則是用於模擬遞迴呼叫並記錄lowlink的。

注意這個演算法中兩處更新lowlink的地方。在getnextscc中的更新,是比較下一層的迭代的lowlink和當前迭代的lowlink,並取最小值,可以看作是遞迴版演算法中,遞迴遍歷子節點並返回到當前棧幀後對lowlink進行的更新。而在dfsvisitchildren中,則是將當前節點的dfs序和子節點的lowlink去比較,可以看作遞迴版中如果已經被visit後進行的更新策略。

即使有了強連通分量,也不能代表當前的節點就是迴圈。因為強連通分量的自反性,所以乙個普通的基本塊也是乙個scc,那麼這是候需要根據迴圈的特徵來判斷scc是否是乙個loop。

// 如果節點有多餘乙個或者有指向自身的邊,說明是個迴圈

template

bool scc_iterator::

hasloop()

const

還有一些迭代器的常規操作:

bool operator==

(const scc_iterator &x)

const

scc_iterator &operator++()

Tarjan(強連通模板)

1 有向圖中,該圖中的任意兩點之間可互達。2 乙個乙個點也是強連通分量 1 時間戳 dfn x 時間戳是用來標記圖中每個節點在進行深度優先搜尋時被訪問的時間順序,當然,你可以理解成乙個序號 這個序號由小到 大 用 dfn x 來表示 搜到該點的最早時間 2 low陣列 2 low陣列 low x 表...

強連通分量 tarjan

洛谷 p2812 校園網路 洛谷 p3387 縮點 include include include include include using namespace std struct arrbot 1100000 d 1100000 int head 20000 h 20000 stack 200...

強連通分量 tarjan

struct enodeedge maxm int p maxn ec void inserte int u,int v,int w int dfn maxn ctime,low maxn 時間戳,時間戳計數,祖先時間。int gid maxn gc 分量陣列,分量計數。bool ins maxn ...