前言
使用链表构建图,利用递归、栈实现Prim算法求取最小生成树。
或许实现的结果与最小生成树的定义有区别,下面代码的结果是:穷举所有的节点,获取从任何顶点出发的一条最小权重的路径。
代码:for v in g.vertices(): 是从所有顶点出发,如果需要从指定顶点出发可以修改为,如设置从a出发:v = g.get_vertex(“a”)。将这行代码替换for 循环即可。(或许这里无法理解,当你对照着代码可能会理解)
此代码是博主自己实现,可能存在一些找不全、甚至找不到结果的极端情况,如有错误敬请指正。
文件集合:
完整代码见GitHub:
https://github.com/GYT0313/Python-DataStructure/tree/master/10-graph/example-TestGraph
1. 运行示例
图结构:
代码界面:
图的实现可以从键盘输入 or 从文件读取:
- 从键盘输入
- 从文件读取
查看图:
生成最小生成树:
2. Prim代码
完整运行代码见GitHub:
https://github.com/GYT0313/Python-DataStructure/tree/master/10-graph/example-TestGraph
Prim代码(algorithms.py):
def span_tree(g, start_label):
"""最小生成树"""
# sys.setrecursionlimit(1500) # set the maximum depth as 1500
min_weights = 99999
results = []
def recurse(w, stack):
if w.is_marked() == False:
# 顶点未标记则入栈
stack.push(w)
w.set_mark()
# 未遍历完的情况
if stack.get_size() != g.size_vertices():
for x in w.neighboring_vertices():
# 继续从顶点的连通节点往下继续遍历
recurse(x, stack)
# 如果从w的连通节点再往下没有连通节点,
# 则出栈w已入栈的连通节点
if stack.peek() != w and \
stack.get_size() < g.size_vertices():
temp = stack.pop()
temp.clear_mark()
else:
# 已经遍历完所有顶点,并且满足了条件,
# 但最后一个节点还有连通的顶点时,不再遍历
# if w.get_edge_count() > 0:
# return None
pass
else:
return None
def generate_results(sun_stack):
temp = ""
for v_temp in sun_stack:
temp += v_temp.get_label() + "->"
temp = temp[:len(temp) - 2]
temp += ": " + str(sun_stack.get_weights())
temp += "\n"
results.append(temp)
for v in g.vertices():
# stack存储整个顶点, sun_stack复制stack的最新状态并继续遍历
stack = LinkedStack()
stack.push(v)
sun_stack = copy.deepcopy(stack)
for w in v.neighboring_vertices():
# 清除所有顶点的标记状态(因为上一次的遍历顶点已经被标记)
g.clear_vertex_marks()
v.set_mark()
# 递归遍历
recurse(w, sun_stack)
# 如果遍历结束,栈内顶点数==图的顶点数代表该次遍历成功,加入成功列表
if sun_stack.get_size() == g.size_vertices():
if sun_stack.get_weights() < min_weights:
results.clear()
generate_results(sun_stack)
min_weights = sun_stack.get_weights()
elif sun_stack.get_weights() == min_weights:
generate_results(sun_stack)
else:
# 未找到路径则继续下一个连接顶点的遍历
pass
sun_stack = copy.deepcopy(stack)
if results == None:
return "No best path"
string = "Here are " + str(len(results)) + " path:\n"
results.insert(0, string)
return results
3. 另一个示例
这个示例用2018年五一数学建模A题为例。
问题1.从景石(a)出发,步行游览以下景点: ①游客服务中心,②阳光草坪,③森林小剧场,④儿童科普体验区,⑤儿童戏水场,⑥湿地博物馆,⑦湿地商业街。建立数学模型,找出从景石出发,到达⑦湿地商业街,并且经过①—⑥所有景点至少1次的距离最短的路线,计算该路线的长度,并将相关结果填入表格3。注:在每个景点不用停留。
对其改编,从任何节点出发,并且不能重复。(符合代码,不然也可以更改代码来符合题意)
原数据:
准备数据:
文件:51.txt
a->b:300 a->c:360 a->d:210 a->e:590 a->f:475 a->g:500 a->h:690
b->a:300 b->c:380 b->d:270 b->e:230 b->f:285 b->g:200 b->h:390
c->a:360 c->b:380 c->d:510 c->e:230 c->f:765 c->g:580 c->h:770
d->a:210 d->b:270 d->c:510 d->e:470 d->f:265 d->g:450 d->h:640
e->a:590 e->b:230 e->c:230 e->d:470 e->f:515 e->g:260 e->h:450
f->a:475 f->b:285 f->c:765 f->d:265 f->e:515 f->g:460 f->h:650
g->a:500 g->b:200 g->c:580 g->d:450 g->e:260 g->f:460 g->h:190
h->a:690 h->b:390 h->c:760 h->d:640 h->e:450 h->f:650 h->g:190
生成图:
运行:
1835 = 265 + 210 + 300 + 380 + 230 +260 + 190
如果有错误或优化请指正。