网络算法——BFS与DFS搜索算法

文章介绍了一个使用邻接表存储的图类定义,包括添加、删除节点和边的方法。在寻找两点间路径时,利用深度优先搜索(DFS)算法,通过递归和路径记录避免重复节点。源代码展示了如何实现DFS找到从s到t的路径,并提供了交互式操作图的简单命令行程序。
摘要由CSDN通过智能技术生成

一、 设计思路:

定义图类存储,采用邻接表的逻辑存储方式,使用字典来实现。

定义图类:

类名: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=[]):寻找两点路径

二、 效果显示

输入:

img

该图实际样式为:

img

输出:

从s到t共有四条路径
image-20230624154729423

三、 遇到的疑惑

寻找两点之间的简单路径,显而易见的是使用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') 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值