图、深度优先(DFS)、广度优先(BFS)

基本介绍

表示方式

图的创建

from typing import List


class Graph:
    vertex_list: List[str] = []  # 存储顶点的数组
    edges: List[list] = []  # 存储图中各条边的邻接矩阵
    num_edges: int = 0  # 边的数总数

    def __init__(self, n: int):
        """
        根据传入的顶点个数初始化顶点数组和邻接矩阵
        n: 图中的顶点个数
        """
        for i in range(n):
            arr = []
            for j in range(n):
                arr.append(0)
            self.edges.append(arr)

    def insert_vertex(self, vertex_val: str):
        """
        添加顶点
        vertex_val: 顶点的值
        """
        self.vertex_list.append(vertex_val)

    def insert_edge(self, v1: int, v2: int, weight: int = 0):
        """
        添加边
        v1: 边的起始顶点的下标,从0开始
        v2: 边的结束顶点的下标,从0开始
        weight: 权值,为1表示两个顶点之间存在边,为0表示两个顶点没有边
        如 A——B ,v1 表示顶点A的下标0,v2表示顶点B的下标1,
        AB之间存在边,所以weight=1
        """
        # 因为是无向图,所以两个顶点对应的位置都要设置边
        self.edges[v1][v2] = weight
        self.edges[v2][v1] = weight
        self.num_edges += 1  # 边的数量加1

    def show_graph(self):
        """
        遍历邻接矩阵
        """
        for arr in self.edges:
            for i in arr:
                print(i, end=' ')
            print()

    def get_num_vertex(self) -> int:
        """
        返回图中的顶点个数
        """
        return len(self.vertex_list)

    def get_num_edge(self) -> int:
        """
        返回图中边的数量
        """
        return self.num_edges

    def get_vertex_val_by_index(self, i: int) -> str:
        """
        根据顶点下标返回顶点的值
        如传入下标0,返回A
        """
        return self.vertex_list[i]

    def get_weight(self, v1: int, v2: int) -> int:
        """
        返回两个顶点之间边的权值
        """
        return self.edges[v1][v2]


def test_graph():
    n = 5
    vertex_arr = ['A', 'B', 'C', 'D', 'E']
    graph = Graph(n)

    # 向图中循环添加顶点
    for i in vertex_arr:
        graph.insert_vertex(i)

    # 添加边
    graph.insert_edge(0, 1, 1)
    graph.insert_edge(0, 2, 1)
    graph.insert_edge(1, 2, 1)
    graph.insert_edge(1, 3, 1)
    graph.insert_edge(1, 4, 1)
    # 显示图的邻接矩阵
    graph.show_graph()


test_graph()

图的深度优先遍历

基本介绍

代码实现

from typing import List


class Graph:
    vertex_list: List[str] = []  # 存储顶点的数组
    edges: List[list] = []  # 存储图中各条边的邻接矩阵
    num_edges: int = 0  # 边的数总数
    is_visited: List[bool] = []  # 标记一个节点是否被访问

    def __init__(self, n: int):
        """
        根据传入的顶点个数初始化顶点数组和邻接矩阵
        n: 图中的顶点个数
        """
        for i in range(n):
            arr = []
            for j in range(n):
                arr.append(0)
            self.edges.append(arr)
            self.is_visited.append(False)

    def get_first_neighbor(self, index: int):
        """
        返回节点第一个邻接节点的下标,如果节点没有邻接节点则返回-1
        """
        for i in range(len(self.vertex_list)):
            if self.edges[index][i] > 0:
                return i

        return -1

    def get_next_neighbor(self, v1: int, v2: int):
        """
        根据节点v1的前一个邻接节点的下标v2获取节点v1的下一个邻接节点的下标
        """
        for i in range(v2 + 1, len(self.vertex_list)):
            if self.edges[v1][i] > 0:
                return i

        return -1

    def dfs(self, i: int):
        """
        深度优先遍历
        :param i: 从节点i开始遍历
        :return:
        """
        # 访问节点i,即输出它
        print(self.vertex_list[i], end=' -> ')
        self.is_visited[i] = True
        # 获取节点i的下一个邻接节点
        w = self.get_first_neighbor(i)
        # 如果节点i的下一个邻接节点w存在
        while w != -1:
            if not self.is_visited[w]:  # 如果w没有被访问过,则从节点w开始继续深度遍历
                self.dfs(w)
            # 如果w已经被访问过,则从节点i的另一个邻接点开始遍历
            w = self.get_next_neighbor(i, w)
        # 如果w不存在,则回退到节点v,遍历节点v的下一个邻接点
        # 所谓的回溯,就是返回到调用dfs()的地方继续执行

    def for_dfs(self):
        """
        遍历所有顶点,看是否存在没有访问过的节点
        """
        for i in range(self.get_num_vertex()):
            if not self.is_visited[i]:  # 存在没有访问过的节点,以该节点进行深度优先遍历
                self.dfs(i)

    def insert_vertex(self, vertex_val: str):
        """
        添加顶点
        vertex_val: 顶点的值
        """
        self.vertex_list.append(vertex_val)

    def insert_edge(self, v1: int, v2: int, weight: int = 0):
        """
        添加边
        v1: 边的起始顶点的下标,从0开始
        v2: 边的结束顶点的下标,从0开始
        weight: 权值,为1表示两个顶点之间存在边,为0表示两个顶点没有边
        如 A——B ,v1 表示顶点A的下标0,v2表示顶点B的下标1,
        AB之间存在边,所以weight=1
        """
        # 因为是无向图,所以两个顶点对应的位置都要设置边
        self.edges[v1][v2] = weight
        self.edges[v2][v1] = weight
        self.num_edges += 1  # 边的数量加1

    def show_graph(self):
        """
        遍历邻接矩阵
        """
        for arr in self.edges:
            for i in arr:
                print(i, end=' ')
            print()

    def get_num_vertex(self) -> int:
        """
        返回图中的顶点个数
        """
        return len(self.vertex_list)


def test_graph():
    n = 5
    vertex_arr = ['A', 'B', 'C', 'D', 'E']
    graph = Graph(n)

    # 向图中循环添加顶点
    for i in vertex_arr:
        graph.insert_vertex(i)

    # 添加边
    graph.insert_edge(0, 1, 1)
    graph.insert_edge(0, 2, 1)
    graph.insert_edge(1, 2, 1)
    graph.insert_edge(1, 3, 1)
    graph.insert_edge(1, 4, 1)
    # 显示图的邻接矩阵
    graph.show_graph()
    print("深度优先遍历:", end='')
    graph.for_dfs()


test_graph()

图的广度优先遍历

基本介绍

代码实现

from typing import List


class Graph:
    vertex_list: List[str] = []  # 存储顶点的数组
    edges: List[list] = []  # 存储图中各条边的邻接矩阵
    num_edges: int = 0  # 边的数总数
    is_visited: List[bool] = []  # 标记一个节点是否被访问

    def __init__(self, n: int):
        """
        根据传入的顶点个数初始化顶点数组和邻接矩阵
        n: 图中的顶点个数
        """
        for i in range(n):
            arr = []
            for j in range(n):
                arr.append(0)
            self.edges.append(arr)
            self.is_visited.append(False)

    def get_first_neighbor(self, index: int):
        """
        返回节点第一个邻接节点的下标,如果节点没有邻接节点则返回-1
        """
        for i in range(len(self.vertex_list)):
            if self.edges[index][i] > 0:
                return i

        return -1

    def get_next_neighbor(self, v1: int, v2: int):
        """
        根据节点v1的前一个邻接节点的下标v2获取节点v1的下一个邻接节点的下标
        """
        for i in range(v2 + 1, len(self.vertex_list)):
            if self.edges[v1][i] > 0:
                return i

        return -1

    def bfs(self, i: int):
        """
        对一个节点进行广度优先遍历
        :param i: 节点的下标
        """
        que = []  # 用列表模拟队列,存储已访问过的节点
        # 输出节点信息
        print(self.vertex_list[i], end=' -> ')
        # 标记节点为已访问
        self.is_visited[i] = True
        que.append(i)  # 将已访问过的节点的下标加入队列
        while que:  # 队列不为空,对节点i的广度优先遍历就继续
            # 取出队头节点的下标u
            u = que.pop(0)
            # 获取节点u的第一个邻接节点的下标w
            w = self.get_first_neighbor(u)
            # 如果节点w存在
            while w != -1:
                # 如果节点w未被访问,则访问并将节点w入队
                if not self.is_visited[w]:
                    print(self.vertex_list[w], end=' -> ')
                    self.is_visited[w] = True
                    que.append(w)
                # 查找节点u继节点w后的另一个邻接节点
                w = self.get_next_neighbor(u, w)

    def for_bfs(self):
        """
        遍历所有顶点,看还有哪一个没有访问过,如果有,则从没有访问过的顶点开始广度优先遍历
        :return:
        """
        for i in range(len(self.vertex_list)):
            if not self.is_visited[i]:
                self.bfs(i)

    def insert_vertex(self, vertex_val: str):
        """
        添加顶点
        vertex_val: 顶点的值
        """
        self.vertex_list.append(vertex_val)

    def insert_edge(self, v1: int, v2: int, weight: int = 0):
        """
        添加边
        v1: 边的起始顶点的下标,从0开始
        v2: 边的结束顶点的下标,从0开始
        weight: 权值,为1表示两个顶点之间存在边,为0表示两个顶点没有边
        如 A——B ,v1 表示顶点A的下标0,v2表示顶点B的下标1,
        AB之间存在边,所以weight=1
        """
        # 因为是无向图,所以两个顶点对应的位置都要设置边
        self.edges[v1][v2] = weight
        self.edges[v2][v1] = weight
        self.num_edges += 1  # 边的数量加1

    def show_graph(self):
        """
        遍历邻接矩阵
        """
        for arr in self.edges:
            for i in arr:
                print(i, end=' ')
            print()


def test_graph():
    n = 5
    vertex_arr = ['A', 'B', 'C', 'D', 'E']
    graph = Graph(n)

    # 向图中循环添加顶点
    for i in vertex_arr:
        graph.insert_vertex(i)

    # 添加边
    graph.insert_edge(0, 1, 1)
    graph.insert_edge(0, 2, 1)
    graph.insert_edge(1, 2, 1)
    graph.insert_edge(1, 3, 1)
    graph.insert_edge(1, 4, 1)
    # 显示图的邻接矩阵
    graph.show_graph()
    print("广度优先遍历:", end='')
    graph.for_bfs()


test_graph()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值