首页 > 代码库 > Program in Lua中图算法的改进(打印所有图路径)

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

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

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

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

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

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

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

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

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

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

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

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

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

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


正文

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

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

内容如下所示:

a b 
b c
b f 
c d
c f
d e
f g
g h
f i
i j
j c
j k
i l
c k 
k l

示意图如下

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



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

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

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

Graph = {}
--生成图节点
function Graph.newNode(graph, name)
	if not graph[name] then
		graph[name] = {name = name, adj={}} --创建一个新的图结点
	end
	return 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 		--连接图结点路径
	end
	return graph
end

function 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 p
	for 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 --找不到,取消一个子table
		p = rightPath or p   --有路径时记录最后一条通路返回,否则返回nil
	end
	
	if 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, " ")      --打印本结点名字和空格符
	end
	
	local 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, " ")
				end
			end
			Graph.printPath(path[i], visited) --然后再次递归搜索下一条支路
		end
	end
	visited[#visited] = nil           --支路已搜索完毕,此分支不再搜索,退化
end

local graph = Graph.gen("./lua/graph.lua")         --生成图
local path = Graph.findpath(graph["a"], graph["l"]) --寻找图路径
Graph.printPath(path)								--输出图路径


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




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