Daniel@0: function [d, pre, post, cycle, f, pred] = dfs(adj_mat, start, directed) Daniel@0: % DFS Perform a depth-first search of the graph starting from 'start'. Daniel@0: % [d, pre, post, cycle, f, pred] = dfs(adj_mat, start, directed) Daniel@0: % Daniel@0: % Input: Daniel@0: % adj_mat(i,j)=1 iff i is connected to j. Daniel@0: % start is the root vertex of the dfs tree; if [], all nodes are searched Daniel@0: % directed = 1 if the graph is directed Daniel@0: % Daniel@0: % Output: Daniel@0: % d(i) is the time at which node i is first discovered. Daniel@0: % pre is a list of the nodes in the order in which they are first encountered (opened). Daniel@0: % post is a list of the nodes in the order in which they are last encountered (closed). Daniel@0: % 'cycle' is true iff a (directed) cycle is found. Daniel@0: % f(i) is the time at which node i is finished. Daniel@0: % pred(i) is the predecessor of i in the dfs tree. Daniel@0: % Daniel@0: % If the graph is a tree, preorder is parents before children, Daniel@0: % and postorder is children before parents. Daniel@0: % For a DAG, topological order = reverse(postorder). Daniel@0: % Daniel@0: % See Cormen, Leiserson and Rivest, "An intro. to algorithms" 1994, p478. Daniel@0: Daniel@0: n = length(adj_mat); Daniel@0: Daniel@0: global white gray black color Daniel@0: white = 0; gray = 1; black = 2; Daniel@0: color = white*ones(1,n); Daniel@0: Daniel@0: global time_stamp Daniel@0: time_stamp = 0; Daniel@0: Daniel@0: global d f Daniel@0: d = zeros(1,n); Daniel@0: f = zeros(1,n); Daniel@0: Daniel@0: global pred Daniel@0: pred = zeros(1,n); Daniel@0: Daniel@0: global cycle Daniel@0: cycle = 0; Daniel@0: Daniel@0: global pre post Daniel@0: pre = []; Daniel@0: post = []; Daniel@0: Daniel@0: if ~isempty(start) Daniel@0: dfs_visit(start, adj_mat, directed); Daniel@0: end Daniel@0: for u=1:n Daniel@0: if color(u)==white Daniel@0: dfs_visit(u, adj_mat, directed); Daniel@0: end Daniel@0: end Daniel@0: Daniel@0: Daniel@0: %%%%%%%%%% Daniel@0: Daniel@0: function dfs_visit(u, adj_mat, directed) Daniel@0: Daniel@0: global white gray black color time_stamp d f pred cycle pre post Daniel@0: Daniel@0: pre = [pre u]; Daniel@0: color(u) = gray; Daniel@0: time_stamp = time_stamp + 1; Daniel@0: d(u) = time_stamp; Daniel@0: if directed Daniel@0: ns = children(adj_mat, u); Daniel@0: else Daniel@0: ns = neighbors(adj_mat, u); Daniel@0: ns = setdiff(ns, pred(u)); % don't go back to visit the guy who called you! Daniel@0: end Daniel@0: for v=ns(:)' Daniel@0: %fprintf('u=%d, v=%d, color(v)=%d\n', u, v, color(v)) Daniel@0: switch color(v) Daniel@0: case white, % not visited v before (tree edge) Daniel@0: pred(v)=u; Daniel@0: dfs_visit(v, adj_mat, directed); Daniel@0: case gray, % back edge - v has been visited, but is still open Daniel@0: cycle = 1; Daniel@0: %fprintf('cycle: back edge from v=%d to u=%d\n', v, u); Daniel@0: case black, % v has been visited, but is closed Daniel@0: % no-op Daniel@0: end Daniel@0: end Daniel@0: color(u) = black; Daniel@0: post = [post u]; Daniel@0: time_stamp = time_stamp + 1; Daniel@0: f(u) = time_stamp; Daniel@0: Daniel@0: