一、 设计思路:
定义图类存储,采用邻接表的逻辑存储方式,使用字典来实现。
定义图类:
类名:Graph
类属性:
-
self.graph = dict() 字典,存储图中的节点和边信息
-
self.nodes = 0 记录图的节点数
-
self.vexs = 0 记录图的边数
类方法:
类方法 | 作用 |
---|---|
def _init_(self): | 初始化类 |
def _str_(self): | 返回类的信息 |
def AddNodeAndVex(self, node, vex): | 增添节点和边 |
def AddNode(self, node): | 增添节点 |
def AddVex(self, node, vex): | 增添边 |
def DelNode(self, node): | 删除节点 |
def DelVex(self, begin, end): | 删除边 |
def FindRoad(self, start, end, path=[]): | 寻找两点路径 |
二、 效果显示
输入:
该图实际样式为:
输出:
从s到t共有四条路径
三、 遇到的疑惑
寻找两点之间的简单路径,显而易见的是使用DFS算法,但是常规的DFS算法只是达到遍历节点的目的,并不能记录路径。
关键的一点在于,在到达目标节点时候要记录下当前的路径,并且能回溯到上一个状态,故而我们在函数中定义了path变量,记录先前的路径,也能作为“闭集“来规避重复节点的访问,在到达目标节点的时候,我们需要”回溯“到上一个状态,这就促使我们使用递归的方式。
在使用DFS算法的时候,感到疑惑的是,发现时间和完成时间,以及节点的入栈方式,在以前的数据结构学习中,不同于现在的每次只入栈一个元素,数据结构中将节点的所有元素一次性入栈,同时当前节点出栈,即第一个访问的节点第一次就“变黑“。这和我们现在学习的DFS是完全不同的。这就导致了在初始不知道使用那种方式
思考之后发现,虽然两者都能按照“深度“的方式将所有节点访问,但是课上学习的发现时间和完成时间更贴合深度遍历的思想,也能更好的记录路径,而先前数据结构学习的DFS只是达到了将节点访问的效果。
四、 源代码
# 时间:2021/9/23 18:03
"""
graph类定义了增加节点和边 增加节点 增加边 删除节点 删除边 打印图的方法
graph采用字典的存储方式
"""
class Graph():
def __init__(self):
self.graph = dict()
self.nodes = 0
self.vexs = 0
def __str__(self):
ans = ''
for item in self.graph:
ans += f'{item} : {self.graph[item]}\n'
ans += f'Nodes:{self.nodes}\n'
ans += f'Vexs:{self.vexs}\n'
return ans
def AddNodeAndVex(self, node, vex):
"""
:type node:str
:type vex:list
:return:
"""
self.graph.update({node: vex})
self.nodes += 1
self.vexs += len(vex)
def AddNode(self, node):
"""
:type node:str
:return:
"""
if node in self.graph.keys():
print(f'{node} already existed!')
return
self.graph.update({node: list()})
self.nodes += 1
def AddVex(self, node, vex):
"""
:type node:str
:type vex:list
:return:
"""
if node not in self.graph.keys():
print(f'{node} not existed!')
return
for item in vex:
if item not in self.graph[node]:
self.graph[node].append(item)
self.vexs += 1
def DelNode(self, node):
"""
:type node:str
:return:
"""
if node not in self.graph.keys():
print(f'{node} not existed!')
return
self.vexs -= len(self.graph[node])
self.graph.pop(node)
self.nodes -= 1
for item in self.graph.values():
if node in item:
item.remove(node)
self.vexs -= 1
def DelVex(self, begin, end):
"""
:type begin:str
:type end:str
:return:
"""
if begin not in self.graph.keys():
print(f'node:{begin} not existed!')
return
if end not in self.graph[begin]:
print('vex not existed!')
self.graph[begin].remove(end)
self.vexs -= 1
def FindRoad(self, start, end, path=[]):
"""
:type start: str
:type end: str
:type path:list
:return: None
"""
# 将当前节点加入路径
path.append(start)
# 如果到达终点 打印路径
if start == end:
print('Find road:', end='')
for i in range(len(path) - 1):
print(path[i], end=' → ')
print(end)
# 返回到上一节点”回溯“
return
# 记录当前节点的邻居
neighbor = self.graph[start]
for item in neighbor:
if item not in path:
# 如果当前节点未被访问 进入递归
self.FindRoad(item, end, path)
# 恢复现场
path.pop()
if __name__ == '__main__':
"""
# 测试用例 需要请取消注释 使用的是ppt上讲DFS BFS的那个图
test = {
'v': ['r'],
'r': ['v', 's'],
's': ['w', 'r'],
'w': ['x', 't', 's'],
'x': ['w', 't', 'u', 'y'],
't': ['w', 'x', 'u'],
'u': ['t', 'x', 'y'],
'y': ['u', 'x'],
}
g = Graph()
for item in test:
g.AddNodeAndVex(item, test[item])
print(g)
g.FindRoad('s', 't', [])
"""
g = Graph()
while True:
print(
'1 for add node and vex\n2 for show road\n3 for add node\n4 for add vex\n5 for del node\n6 for del vex\n7 for show graph\n0 for end program')
choose = input('Plz input your choice:')
if choose == '1':
print("plz input as n1:v1,v2 and press enter for next input")
print('press # to end input')
print("example a:b,c,d")
try:
while True:
s = input(':')
temp = s.split(':')
node = temp[0]
vex = temp[1].split(',')
g.AddNodeAndVex(node, vex)
except:
print('input ended current graph is:')
print(g)
elif choose == '2':
print('plz input start and end')
start = input('start:')
end = input('end:')
g.FindRoad(start, end)
elif choose == '3':
print('plz input the node you are going to add')
node = input(':')
g.AddNode(node)
print('done')
elif choose == '4':
print('plz input the vex you are going to add')
begin = input('begin:')
end = input('end:')
g.AddVex(begin, [end])
print('done')
elif choose == '5':
print('plz input the node you are going to del')
d = input(':')
g.DelNode(d)
print('done')
elif choose == '6':
print('plz input the vex you are going to del')
begin = input('begin:')
end = input('end:')
g.DelVex(begin, end)
print('done')
elif choose == '7':
print(g)
elif choose == '0':
break
else:
print('wrong input')