summaryrefslogtreecommitdiff
path: root/xmake/core/base/graph.lua
diff options
context:
space:
mode:
authorruki <[email protected]>2023-09-30 00:36:53 +0800
committerruki <[email protected]>2023-09-30 00:36:53 +0800
commit5a2c5c458af38dd90924f251d518b97ba2cf604b (patch)
tree78ded54f7a54fd35ccd58c417a3178e18911dbca /xmake/core/base/graph.lua
parentc8f60856c4c998f3d4894524ba1576f8da43baa7 (diff)
find cycle in graph
Diffstat (limited to 'xmake/core/base/graph.lua')
-rw-r--r--xmake/core/base/graph.lua76
1 files changed, 68 insertions, 8 deletions
diff --git a/xmake/core/base/graph.lua b/xmake/core/base/graph.lua
index 875bceb45..80d4566ec 100644
--- a/xmake/core/base/graph.lua
+++ b/xmake/core/base/graph.lua
@@ -113,32 +113,76 @@ end
-- topological sort
function graph:topological_sort()
- local marked = {}
+ local visited = {}
for _, v in ipairs(self:vertices()) do
- marked[v] = false
+ visited[v] = false
end
local order_vertices = {}
- local function graph_topological_sort_dfs(v)
- marked[v] = true
+ local function dfs(v)
+ visited[v] = true
local edges = self:adjacent_edges(v)
if edges then
for _, e in ipairs(edges) do
local w = e:other(v)
- if marked[w] == false then
- graph_topological_sort_dfs(w)
+ if not visited[w] then
+ dfs(w)
end
end
end
table.insert(order_vertices, v)
end
for _, v in ipairs(self:vertices()) do
- if marked[v] == false then
- graph_topological_sort_dfs(v)
+ if not visited[v] then
+ dfs(v)
end
end
return table.reverse(order_vertices)
end
+-- find cycle
+function graph:find_cycle()
+ local visited = {}
+ local stack = {}
+ local cycle = {}
+
+ local function dfs(v)
+ visited[v] = true
+ stack[v] = true
+ table.insert(cycle, v)
+ local edges = self:adjacent_edges(v)
+ if edges then
+ for _, e in ipairs(edges) do
+ local w = e:other(v)
+ if not visited[w] then
+ if dfs(w) then
+ return true
+ elseif stack[w] then
+ return true
+ end
+ elseif stack[w] then
+ for i = #cycle, 1, -1 do
+ if cycle[i] == w then
+ cycle = table.slice(cycle, i)
+ return true
+ end
+ end
+ end
+ end
+ end
+ table.remove(cycle)
+ stack[v] = false
+ return false
+ end
+
+ for _, v in ipairs(self:vertices()) do
+ if not visited[v] then
+ if dfs(v) then
+ return cycle
+ end
+ end
+ end
+end
+
-- get edges
function graph:edges()
return self._edges
@@ -208,6 +252,22 @@ function graph:reverse()
return gh
end
+-- dump graph
+function graph:dump()
+ local vertices = self:vertices()
+ local edges = self:edges()
+ print(string.format("graph: %s, vertices: %d, edges: %d", self:is_directed() and "directed" or "not-directed", #vertices, #edges))
+ print("vertices: ")
+ for _, v in ipairs(vertices) do
+ print(string.format(" %s", v))
+ end
+ print("")
+ print("edges: ")
+ for _, e in ipairs(edges) do
+ print(string.format(" %s -> %s", e:from(), e:to()))
+ end
+end
+
-- new graph
function graph.new(directed)
local gh = graph {directed}