图的遍历

从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历。

(1)深度优先遍历#

深度优先遍历类似于数的先序遍历,是树的先序遍历的推广。

  • 从图中某个顶点v出发,访问v。

  • 找到刚访问过得顶点的第一个未被访问的邻接点,访问该顶点。以该顶点为新顶点,重复此步骤,直至刚访问的顶点没有未被访问的邻接点为止。

  • 返回前一个访问过得且扔有未被访问的邻接点的顶点,找到该顶点的下一个未被访问的邻接点,访问该顶点。

  • 重复步骤2,3,直至图中所有顶点都被访问过。

    img

    深度优先遍历算法的实现

    为了在遍历过程中便于区分顶点是否已经被访问,需附设访问标志组visited,其初值为false,一旦某个顶点被访问,则其相应的分量置为true。

    # python代码实现邻接矩阵的深度优先遍历
    class MGraph():
        def __init__(self):
            self.vertex = []
            self.matrix = []
            self.numNodes = 0
            self.numEdges = 0
            self.visited = []
    
        def createMGraph(self):
            """创建无向图的邻接矩阵表示"""
            self.numNodes = int(input("请输入顶点数:"))
            self.numEdges = int(input("请输入边数:"))
            for i in range(self.numNodes):
                self.vertex.append(input("请输入一个顶点:"))
    
            for i in range(self.numNodes):
                self.matrix.append([])
                for j in range(self.numNodes):
                    self.matrix[i].append(0)  # 初始化邻接矩阵
    
            for k in range(self.numEdges):  # 读入numEdges条边,建立邻接矩阵
                i = int(input("请输入边(vi,vj)上的下标i:"))
                j = int(input("请输入边(vi,vj)上的下标j:"))
                self.matrix[i][j] = 1
                self.matrix[j][i] = self.matrix[i][j]  # 因为是无向网图,矩阵对称
    
        def viewMGraphStruct(self):
            print(self.matrix)
    
        def DFS(self, i):
            """零阶矩阵的深度优先递归算法"""
            self.visited[i] = True
            print(self.vertex[i])
            for j in range(self.numNodes):
                if self.matrix[i][j] == 1 and not self.visited[j]:
                    self.DFS(j)
    
        def DFSTraverse(self):
            """邻接矩阵的深度优先遍历操作"""
            self.visited = [False for i in range(self.numNodes)]
            for i in range(self.numNodes):
                if not self.visited[i]:  # 对未访问过的顶点调用DFS,若为连通图仅执行一次
                    self.DFS(i)
    
    
    if __name__ == '__main__':
        G = MGraph()
        G.createMGraph()
        G.viewMGraphStruct()
        print("深度优先遍历结果如下:")
        G.DFSTraverse()
    

    此代码包含了无向图的邻接矩阵存储方式的创建,以及深度优先遍历算法,既能遍历连通图也能遍历非联通图。

    以上面的图为例,代码运行后,我们输入图的信息创建图,生成的邻接矩阵以及深度优先遍历结果如下:

    邻接矩阵:
    [[0, 1, 0, 0, 0, 1, 0, 0, 0], 
    [1, 0, 1, 0, 0, 0, 1, 0, 1], 
    [0, 1, 0, 1, 0, 0, 0, 0, 1], 
    [0, 0, 1, 0, 1, 0, 1, 1, 1], 
    [0, 0, 0, 1, 0, 1, 0, 1, 0], 
    [1, 0, 0, 0, 1, 0, 1, 0, 0], 
    [0, 1, 0, 1, 0, 1, 0, 1, 0], 
    [0, 0, 0, 1, 1, 0, 1, 0, 0], 
    [0, 1, 1, 1, 0, 0, 0, 0, 0]]
    
    深度优先遍历结果如下:
    A
    B
    C
    D
    E
    F
    G
    H
    I
    

    python代码实现邻接表的深度优先遍历:

    class Vertex(object):
        """创建Vertex类,用来存放顶点信息(包括data和firstEdge)"""
    
        def __init__(self, data=None):
            self.data = data
            self.firstEdge = None
    
    
    class EdgeNode(object):
        """ 创建Edge类,用来存放边信息(包括adjVex和next);"""
    
        def __init__(self, adjVex):
            self.adjVex = adjVex
            self.next = None
    
    
    class ALGraph():
        """无向图类"""
    
        def __init__(self):
            self.numNodes = 0
            self.numEdges = 0
            self.adjList = []
            self.visited = []
    
        def createALGraph(self):
            self.numNodes = int(input("输入顶点数:"))
            self.numEdges = int(input("输入边数:"))
            for i in range(self.numNodes):  # 读入顶点信息,建立顶点表
                v = Vertex()
                self.adjList.append(v)
                self.adjList[i].data = input("请输入顶点数据:")
    
            for k in range(self.numEdges):  # 建立边表
                i = int(input("请输入边(vi,vj)上的下标i:"))
                j = int(input("请输入边(vi,vj)上的下标j:"))
                e = EdgeNode(j)  # 实例化边节点
                e.next = self.adjList[i].firstEdge  # 将e的指针指向当前顶点指向的节点
                self.adjList[i].firstEdge = e  # 将当前顶点的指针指向e
                e = EdgeNode(i)  # 实例化边节点
                e.next = self.adjList[j].firstEdge  # 将e的指针指向当前顶点指向的节点
                self.adjList[j].firstEdge = e  # 将当前顶点的指针指向e
    
        def DFS(self, i):
            """邻阶表的深度优先递归算法"""
            self.visited[i] = True
            print(self.adjList[i].data)
            p = self.adjList[i].firstEdge
            while p:
                if not self.visited[p.adjVex]:
                    self.DFS(p.adjVex)
                p = p.next
    
        def DFSTraverse(self):
            """邻接表的深度优先遍历操作"""
            self.visited = [False for i in range(self.numNodes)]
            for i in range(self.numNodes):
                if not self.visited[i]:  # 对未访问过的顶点调用DFS,若为联通图仅执行一次
                    self.DFS(i)
    
    
    if __name__ == '__main__':
        G = ALGraph()
        G.createALGraph()
        G.DFSTraverse()
    

    遍历结果如下:

    A
    F
    G
    H
    E
    D
    I
    C
    B
    

    (2)广度优先遍历#

    图的广度优先遍历就类似于树的层序遍历。

  • 从图中某个顶点v出发,访问v。

  • 依次访问v的各个未被访问过得邻接点。

  • 分别从这些邻接点出发依次访问他们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问。重复步骤3,直至图中所有已被访问的顶点的邻接点都被访问到。

    img

    广度优先遍历连通图

    1. 从图中某个顶点v出发,访问v,并置visited[v]的值为true,然后将v进队。
    2. 只要队列不为空,则重复下述操作:
    • 队头顶点u出队。
    • 依次检查u的所有邻接点w,如果visited[w]的值为false,则访问w,并置visited[w]的值为true。然后将w进队。

    python实现邻接矩阵的广度优先遍历:

    class Queue():
        """队列类"""
        def __init__(self):
            self.queue = []
    
        def Enqueue(self, data):
            """入队操作"""
            self.queue.append(data)
    
        def Dequeue(self):
            """出队操作"""
            return self.queue.pop(0)
    
        def isEmpty(self):
            """判断队列是否为空"""
            if len(self.queue) == 0:
                return True
            else:
                return False
    
    
    class MGraph():
        def __init__(self):
            self.vertex = []
            self.matrix = []
            self.numNodes = 0
            self.numEdges = 0
            self.visited = []
    
        def createMGraph(self):
            """创建无向图的邻接矩阵表示"""
            self.numNodes = int(input("请输入顶点数:"))
            self.numEdges = int(input("请输入边数:"))
            for i in range(self.numNodes):
                self.vertex.append(input("请输入一个顶点:"))
    
            for i in range(self.numNodes):
                self.matrix.append([])
                for j in range(self.numNodes):
                    self.matrix[i].append(0)  # 初始化邻接矩阵
    
            for k in range(self.numEdges):  # 读入numEdges条边,建立邻接矩阵
                i = int(input("请输入边(vi,vj)上的下标i:"))
                j = int(input("请输入边(vi,vj)上的下标j:"))
                self.matrix[i][j] = 1
                self.matrix[j][i] = self.matrix[i][j]  # 因为是无向网图,矩阵对称
    
        def viewMGraphStruct(self):
            print(self.matrix)
    
        def BFSTraverse(self):
            """邻接矩阵的广度优先遍历操作"""
            self.visited = [False for i in range(self.numNodes)]  # 初始化所有顶点状态为未访问状态
            Q = Queue()  # 实例化队列Q
            for i in range(self.numNodes):
                if not self.visited[i]:  # 对未访问过的顶点进行处理
                    self.visited[i] = True  # 将当前顶点标记为已访问
                    print(self.vertex[i])  # 打印此顶点
                    Q.Enqueue(i)  # 将此顶点入队列
                    while not Q.isEmpty():  # 若队列不为空
                        i = Q.Dequeue()  # 将队首元素出队列,赋值给i
                        for j in range(self.numNodes):
                            if self.matrix[i][j] == 1 and not self.visited[j]:  # 判断其他顶点,若与当前顶点存在边且未访问过
                                self.visited[j] = True  # 将找到的此顶点标记为已访问
                                print(self.vertex[j])  # 打印此顶点
                                Q.Enqueue(j)  # 将此顶点入队列
    
    
    if __name__ == '__main__':
        G = MGraph()
        G.createMGraph()
        G.viewMGraphStruct()
        print("广度优先遍历结果如下:")
        G.BFSTraverse()
    

    邻接矩阵如下:

    [[0, 1, 0, 0, 0, 1, 0, 0, 0], 
    [1, 0, 1, 0, 0, 0, 1, 0, 1], 
    [0, 1, 0, 1, 0, 0, 0, 0, 1], 
    [0, 0, 1, 0, 1, 0, 1, 1, 1], 
    [0, 0, 0, 1, 0, 1, 0, 1, 0], 
    [1, 0, 0, 0, 1, 0, 1, 0, 0], 
    [0, 1, 0, 1, 0, 1, 0, 1, 0], 
    [0, 0, 0, 1, 1, 0, 1, 0, 0], 
    [0, 1, 1, 1, 0, 0, 0, 0, 0]]
    

    遍历结果如下:

    A
    B
    F
    C
    G
    I
    E
    D
    H
    

    python实现邻接表的广度优先遍历:

    class Queue():
        """队列类"""
    
        def __init__(self):
            self.queue = []
    
        def Enqueue(self, data):
            """入队操作"""
            self.queue.append(data)
    
        def Dequeue(self):
            """出队操作"""
            return self.queue.pop(0)
    
        def isEmpty(self):
            """判断队列是否为空"""
            if len(self.queue) == 0:
                return True
            else:
                return False
    
    
    class Vertex(object):
        """创建Vertex类,用来存放顶点信息(包括data和firstEdge)"""
    
        def __init__(self, data=None):
            self.data = data
            self.firstEdge = None
    
    
    class EdgeNode(object):
        """ 创建Edge类,用来存放边信息(包括adjVex和next);"""
    
        def __init__(self, adjVex):
            self.adjVex = adjVex
            self.next = None
    
    
    class ALGraph():
        """无向图类"""
    
        def __init__(self):
            self.numNodes = 0
            self.numEdges = 0
            self.adjList = []
            self.visited = []
    
        def createALGraph(self):
            self.numNodes = int(input("输入顶点数:"))
            self.numEdges = int(input("输入边数:"))
            for i in range(self.numNodes):  # 读入顶点信息,建立顶点表
                v = Vertex()
                self.adjList.append(v)
                self.adjList[i].data = input("请输入顶点数据:")
    
            for k in range(self.numEdges):  # 建立边表
                i = int(input("请输入边(vi,vj)上的下标i:"))
                j = int(input("请输入边(vi,vj)上的下标j:"))
                e = EdgeNode(j)  # 实例化边节点
                e.next = self.adjList[i].firstEdge  # 将e的指针指向当前顶点指向的节点
                self.adjList[i].firstEdge = e  # 将当前顶点的指针指向e
                e = EdgeNode(i)  # 实例化边节点
                e.next = self.adjList[j].firstEdge  # 将e的指针指向当前顶点指向的节点
                self.adjList[j].firstEdge = e  # 将当前顶点的指针指向e
    
        def BFSTraverse(self):
            """邻接表的深度优先遍历操作"""
            self.visited = [False for i in range(self.numNodes)]
            Q = Queue()
            for i in range(self.numNodes):
                if not self.visited[i]:  # 对未访问过的顶点进行处理
                    self.visited[i] = True  # 将当前顶点标记为已访问
                    print(self.adjList[i].data)  # 打印此顶点
                    Q.Enqueue(i)  # 将此顶点入队列
                    while not Q.isEmpty():  # 若队列不为空
                        i = Q.Dequeue()  # 将队首元素出队列,赋值给i
                        p = self.adjList[i].firstEdge  # 找到当前顶点的边表链的表头指针
                        while p:
                            if not self.visited[p.adjVex]:  # 若此顶点未被访问
                                self.visited[p.adjVex] = True
                                print(self.adjList[p.adjVex].data)
                                Q.Enqueue(p.adjVex)  # 将此顶点入队列
                            p = p.next  # 指针指向下一邻接点
    
    
    if __name__ == '__main__':
        G = ALGraph()
        G.createALGraph()
        G.BFSTraverse()
    

    遍历结果:

    A
    F
    B
    G
    E
    I
    C
    H
    D
    

    本文部分概念内容来自:https://www.jianshu.com/p/d9ca383e2bd8,其余均为自创。

    作者:minqiliang

    出处:https://www.cnblogs.com/minqiliang/p/16835943.html

    版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

    posted @   minqiliang  阅读(153)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
    · Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
    · 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
    · 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
    · 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
    -->
    more_horiz
    keyboard_arrow_up light_mode palette
    选择主题
    menu
    点击右上角即可分享
    微信分享提示