查看我的answer有關強連通組件的更早問題。
你的dfs的寫入效率也很低,因爲你重複掃描i = 0;你的堆棧應該記住你離開的地方並從那裏繼續。遞歸更自然,但如果你有有限的調用堆棧大小,那麼顯式堆棧是最好的(僅適用於巨大的樹)。
這是一個遞歸dfs。如果你不感興趣的存儲DFS樹,你可以存儲1前任[],而不是節點你達到它):
const unsigned MAXNODES=100;
/* predecessor must be 0-initialized by the caller; nodes graph[n] that are
reached from start will have predecessor[n]=p+1, where graph[pred] is the
predecessor via which n was reached from graph[start].
predecessor[start]=MAXNODES+1 (this is the root of the tree; there is NO
predecessor, but instead of 0, I put a positive value to show that it's
reached).
graph[a][b] is true iff there is a directed arc from a->b
*/
void dfs(bool graph[MAXNODES][MAXNODES],unsigned predecessor[]
,unsigned start,unsigned pred=MAXNODES)
{
if (predecessor[start]) return;
predecessor[start]=pred+1;
for (unsigned i=0;i<MAXNODES;++i)
if (graph[start][i])
dfs(graph,predecessor,i,start);
}
這裏有圖案的上述非遞歸DFS,但使用pred
和i
相同的堆棧變量(一般你就必須爲每一個局部變量和參數堆棧變量,可以在你的遞歸改變):
void dfs_iter(bool graph[MAXNODES][MAXNODES],unsigned predecessor[]
,unsigned start)
{
unsigned stack[MAXNODES]; // node indices
unsigned n,pred;
int top=0;
stack[top]=start;
for(;;) {
recurse:
// invariant: stack[top] is the next (maybe reached) node
n=stack[top];
if (!predecessor[n]) { // not started yet
pred=top>0?stack[top-1]:MAXNODES;
//show(n,pred);
predecessor[n]=pred+1;
// the first thing we can reach from n
for (unsigned i=0;i<MAXNODES;++i)
if (graph[n][i] && !predecessor[i]) {
stack[++top]=i; goto recurse; // push
}
}
if (top>0) {
pred=stack[top-1];
// the next thing we can reach from pred after n
for (unsigned i=n+1;i<MAXNODES;++i)
if (graph[pred][i]) {
stack[top]=i; goto recurse; // replace top
}
--top;
} else
return;
}
}
這可能沒有轉到結構化(它只是一個名字繼續到最外面的循環),但在我看來沒有更真實的清晰度。
無論如何,遞歸調用要簡單得多。有Tarjan's strongly connected components algorithm的遞歸僞代碼,你可以直接轉錄。如果您需要幫助使其成爲非遞歸(顯式堆棧),請詢問。
有關非遞歸遞歸的警告:我最初得到dfs_iter時很明顯沒有意識到它。除非你從字面上創建一個堆棧數據結構,該結構的每個局部變量或參數在遞歸中都有一個成員,並且機械地進行翻譯,否則很容易搞砸。只使用一個堆棧(加上輸出的前置數組)使得它變得更加棘手。 – 2009-12-03 02:44:28
dfs_iter的i = n + 1部分正是比你的版本更有效的地方,你總是在i = 0時重新啓動。 – 2009-12-03 02:48:24
什麼顯示(n,pred)呢。你想顯示任何值嗎? – Chaitanya 2009-12-03 04:07:43