80 lines
2.0 KiB
Lua
80 lines
2.0 KiB
Lua
-- adjacency list: adj[u] = {v1, v2, ...}
|
|
local adj = {}
|
|
|
|
local function add_edge(u, v)
|
|
adj[u] = adj[u] or {}
|
|
table.insert(adj[u], v)
|
|
end
|
|
|
|
-- Example graph
|
|
add_edge("A", "B")
|
|
add_edge("B", "C")
|
|
add_edge("C", "D")
|
|
-- Uncomment next line to introduce a cycle:
|
|
add_edge("A", "D")
|
|
|
|
---------------------------------------------------------
|
|
-- Topological sort (DFS-based, with cycle detection)
|
|
---------------------------------------------------------
|
|
local visited = {} -- "perm" mark: node completely processed
|
|
local in_stack = {} -- "temp" mark: node currently in recursion stack
|
|
local order = {} -- reverse topological order
|
|
local cycle = nil -- store cycle if found
|
|
|
|
local function dfs(u, path)
|
|
visited[u] = true
|
|
in_stack[u] = true
|
|
table.insert(path, u)
|
|
|
|
for _, v in ipairs(adj[u] or {}) do
|
|
if not visited[v] then
|
|
dfs(v, path)
|
|
if cycle then return end
|
|
elseif in_stack[v] then
|
|
-- found a cycle
|
|
cycle = {}
|
|
-- extract the cycle part from path
|
|
for i = #path, 1, -1 do
|
|
table.insert(cycle, 1, path[i])
|
|
if path[i] == v then break end
|
|
end
|
|
table.insert(cycle, v) -- close the cycle
|
|
return
|
|
end
|
|
end
|
|
|
|
in_stack[u] = false
|
|
table.remove(path)
|
|
table.insert(order, 1, u)
|
|
end
|
|
|
|
local function topo_sort()
|
|
for u, _ in pairs(adj) do
|
|
if not visited[u] then
|
|
dfs(u, {})
|
|
if cycle then return nil, cycle end
|
|
end
|
|
end
|
|
|
|
-- build rank map
|
|
local rank = {}
|
|
for i, u in ipairs(order) do
|
|
rank[u] = i
|
|
end
|
|
return rank
|
|
end
|
|
|
|
---------------------------------------------------------
|
|
-- Run it
|
|
---------------------------------------------------------
|
|
local rank, cycle = topo_sort()
|
|
if cycle then
|
|
print("Cycle detected:")
|
|
print(table.concat(cycle, " -> "))
|
|
else
|
|
print("Topological order ranks:")
|
|
for k, v in pairs(rank) do
|
|
print(k, v)
|
|
end
|
|
end
|