在sqlite中查找行之间的所有路径

时间:2019-01-10 14:20:41

标签: sqlite

我找不到适合我问题的正确答案,这就是我要问的原因。

我有一个包含uid(整数,唯一)列的Rooms表。 另外我有一个退出表,它具有fromuid(整数)touid(整数)

我想找到所有从uid到目标uid的可能出口。

rooms表具有约32000行。每个房间可以有大约10个通往其他房间的出口。

我想要获取最终到达目标uid的所有可能的行。

1 个答案:

答案 0 :(得分:0)

这是在Lua中做到这一点的方法。

创建一个Lua表,将每个节点的出口保留为节点ID表...

exits = {}

function dbexits(db)
    for fromuid, touid in db:urows('SELECT fromuid, touid from exits') do
        local et = exits[fromuid] or {}
        et[#et+1] = touid
        exits[fromuid] = et
    end
end

使用广度优先搜索来查看是否存在从fmidtoid的路径; seen表可防止路径中的循环无限回归。

function pathexists (fmid, toid)
    local seen = {}
    local work = {fmid}
    while #work > 0 do
        local c = work[#work]
        work[#work] =  nil
        seen[c] = true
        if c == toid then
            return true
        end
        for _,v in pairs(exits[c]) do
            if not seen[v] then work[#work+1] = v end
        end
    end
    return false
end

在源节点的每个出口上使用pathexists函数以查看其是否到达目标节点...

function findexits (sourceid, targetid)
    local result = {}
    local srcexits = exits[sourceid]
    for _,e in pairs(srcexits) do
        if pathexists(e,targetid) then
            result[#result+1] = e
        end
    end
    return result
end

这是一个简单的测试:

sqlite3 = require("lsqlite3")

db = sqlite3.open_memory()

db:exec[[ CREATE TABLE exits (fromuid, touid) ]]

db:exec[[ INSERT INTO exits VALUES (1, 2) ]]
db:exec[[ INSERT INTO exits VALUES (1, 3) ]]
db:exec[[ INSERT INTO exits VALUES (2, 1) ]]
db:exec[[ INSERT INTO exits VALUES (2, 3) ]]
db:exec[[ INSERT INTO exits VALUES (3, 1) ]]
db:exec[[ INSERT INTO exits VALUES (3, 5) ]]
db:exec[[ INSERT INTO exits VALUES (4, 2) ]]
db:exec[[ INSERT INTO exits VALUES (4, 6) ]]
db:exec[[ INSERT INTO exits VALUES (5, 1) ]]
db:exec[[ INSERT INTO exits VALUES (5, 2) ]]
db:exec[[ INSERT INTO exits VALUES (6, 7) ]]
db:exec[[ INSERT INTO exits VALUES (6, 3) ]]
db:exec[[ INSERT INTO exits VALUES (7, 4) ]]
db:exec[[ INSERT INTO exits VALUES (7, 3) ]]

--[[
for row in db:nrows("SELECT * FROM exits") do
  print(row.fromuid, row.touid)
end
]]--

dbexits(db)

--[[
function printf(s,...)
    return io.write(s:format(...))
end
for k,v in pairs(exits) do
    printf("\n%d: ", k)
    for _,e in pairs(v) do
        printf("%d ", e)
    end
end
]]--

e = findexits(1,5)

--[[
for _,v in pairs(e) do print(v) end
]]--

assert(e[1] == 2)
assert(e[2] == 3)

e = findexits(1,4)

assert(#e == 0)

使用Lua 5.4和lsqlite3 v3.24.0通过测试