Program in Lua中图算法的改进(打印所有图路径)

来源:互联网 发布:cmd怎么ping端口 编辑:程序博客网 时间:2024/04/29 04:56

    Program in Lua第二版,第11.7节中介绍了用lua写“图”数据结构的方法,

但书中提供的图的算法只能打印出第一条找到的正确路径,于是我就自己琢磨

着怎么用lua写出一个图算法打印出所有可能的路径,自己独自一个人思考了

很久,期间没有参考任何资料,完全靠“头脑暴力”把它解决了,最后思考了看看,

也不知道这到底是什么算法,完全凭借着自己认为的所谓的"退化"的概念,奇妙

的解决了这个问题,所以我把这个算法拿出来分享一下

(总觉得在哪本书上看到过“退化”这个字眼,但我其实不知道什么是真正的“退化”,

但在我脑海里,“退化”就是一个概念而已,在这里,觉得似乎用这个概念有那么

一点合适的味道,那我就把它称之为“退化”了。另外,也许这个算法也有人实现

过,但我其实并不知道这是什么算法,我只知道这个算法的思想---用我所谓的

退化(因为我学的很少,至少还没去专门学过图论,所以勿喷)如果我这个

设计“的算法你见过,或知道是什么算法可以告诉我(至少我不认为我能想出来

的东西别人会没想到,我应该还没到那种境界吧=_=))


正文

首先是一个保存了图中数据的.lua文件,其名为graph.lua,

相对路径为./lua/graph.lua

内容如下所示:

a b b cb f c dc fd ef gg hf ii jj cj ki lc k k l

示意图如下

(该算法只适用于单向的图)



然后是“”数据结构及我“设计”的这个算法

相对路径为./lua/11.7.lua

(注释写的很详细,都写在代码里面了,不懂的可以问我)

Graph = {}--生成图节点function Graph.newNode(graph, name)if not graph[name] thengraph[name] = {name = name, adj={}} --创建一个新的图结点endreturn graph[name]end--生成图function Graph.gen(s)local graph = {}for line in io.lines(s) do--匹配起始,通往结点local namefrom, nameto = string.match(line, "(%S+)%s(%S+)")local from = Graph.newNode(graph, namefrom) --生成起始结点local to = Graph.newNode(graph, nameto)   --生成通往结点local path = from.adj       --得到路径表path[#path + 1] = to --连接图结点路径endreturn graphendfunction Graph.findpath(curr, to, path, visited)--参数:当前结点, 目的结点, 保存路径的集合, 已访问结点集合(可退化)--关于退化:这里的退化概念是自己提出的,意思是对得到一条通路上的结点--往前回溯取消记录,以致于另一个递归搜素分支可以找到这条路径,同时,--对于已压栈函数记录的结点和无通路径上的结点保存记录以至于递归函数--直接返回path = path or {}         --path作为table来记录所有保存的路径visited = visited or {}   --visited为保存记录结点的表if visited[curr] then     --对记录结点直接返回return nil end visited[curr] = true      --记录访问节点path["name"] = curr["name"]  --记录路径if curr == to then        --找到终点,构成一条路径,返回visited[curr] = nil   --退化(取消该终点的记录)return path          end local pfor i,from in ipairs(curr.adj) do path[i] = {father = path}    --保存一个能找到父结点的字段--递归搜索路径local rightPath = Graph.findpath(from, to, path[i], visited)if not rightPath then path[i] = nil end --找不到,取消一个子tablep = rightPath or p   --有路径时记录最后一条通路返回,否则返回nilendif p then visited[curr] = nil       --退化该路径节点return p["father"]   --返回该路径的father,即本结点end    path = nil                  --没找到,删除该节点end--打印所有图路径function Graph.printPath(path, visited)--路径结点集合, 已访问结点集合(可退化)path = path or {}           visited = visited or {}if path then visited[#visited + 1] = path  --以数组形式保存访问过的路径io.write(path.name, " ")      --打印本结点名字和空格符endlocal maxn = table.maxn(path)     --取可行支路中的最大编号if maxn == 0 then   --不存在支路(即终点)时visited[#visited] = nil       --退化,取消记录该结点io.write("\n")                --该条路径已完全输出,换行return end   --终点,返回local count = 0                   --统计支路的数目for i = 1, maxn do if path[i] then  --该条编号的支路存在count = count + 1  --递增支路数if count > 1 then           --除第一条支路之外,for i,v in ipairs(visited) do --对已记录的根路结点进行打印io.write(v.name, " ")endendGraph.printPath(path[i], visited) --然后再次递归搜索下一条支路endendvisited[#visited] = nil           --支路已搜索完毕,此分支不再搜索,退化endlocal graph = Graph.gen("./lua/graph.lua")         --生成图local path = Graph.findpath(graph["a"], graph["l"]) --寻找图路径Graph.printPath(path)--输出图路径


下面是运行后的输出结果:




1 0