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

news2024/9/24 15:18:13

基本介绍

表示方式

图的创建

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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1152191.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11、插件注入到vue实例中

新建插件 nuxt-demo2\plugins\vue-inject.js import Vue from "vue"Vue.prototype.$test function (str) {console.log(str) }配置插件 nuxt-demo2\nuxt.config.js export default {...// Plugins to run before rendering page: https://go.nuxtjs.dev/config-…

表格识别软件:科技革新引领行业先锋,颠覆性发展前景广阔

表格识别软件的兴起背景可以追溯到数字化和自动化处理的需求不断增加的时期。传统上,手动处理纸质表格是一项费时费力的工作,容易出现错误,效率低下。因此,开发出能够自动识别和提取表格数据的软件工具变得非常重要。 随着计算机…

Xcode运行程序提示 Executable Path is a Directory 问题解决

一、首先运行模拟器报错(没有记录),解决办法: TARGET->Build Settings->Architectures -> Exclude Architectures里面填入arm64,后运行模拟器成功 二、其次模拟器开发完成后,xcode运行真机调试&…

canvas:理解canvas / 基础使用 / Demo效果

一、理解Canvas Canvas是一个HTML5元素,用于在Web页面上绘制2D或3D图形。它允许使用JavaScript在网页上创建和操作图形。Canvas的主要功能是绘图,但也可以用来实现其他功能,如动画和交互式游戏。 使用Canvas,可以创建各种形状、…

【AOP进阶】实现重试机制

📚目录 ⚙️简介:✨注解定义:⛳RetryMechanism ⌛编写AOP代码:⚓RetryMechanismAspect 切面 ⛵演示:⛴如何使用RetryMechanism:⚡️正常请求如下:☘️测试异常并且重试:☄️测试异常…

WSL2 Ubuntu安装CUDA Toolkit

目前CUDA ToolKit需要切换到WSL2,在WLS1下不支持。之前折腾了很久,才从WSL1的坑中爬出来,仅写此文避免大家再从坑里走一次。 Windows WSL2相关 检查正在运行的 WSL 版本 可列出已安装的 Linux 发行版,并通过在 PowerShell 或 W…

Android NDK开发详解之ndk-gdb

Android NDK开发详解之ndk-gdb 要求用法选项 线程支持 NDK 包含一个名为 ndk-gdb 的 Shell 脚本,可以启动命令行原生调试会话。偏好使用 GUI 的用户则应阅读在 Android Studio 中调试这篇文档。 要求 要运行命令行原生调试,必须满足以下要求&#xff1…

SDK 消息处理

目录 消息处理 窗口通知消息处理 鼠标消息 键盘消息 绘图消息 WM_PAINT 客户区与非客户区 WM_PAINT消息 BeginPaint && EndPaint 模仿记事本输入字符功能 定时器 消息处理 窗口的过程函数接收到消息后并且进行处理。平时常用的消息以及官方参考文档&#xf…

“ 1+2+N “打造“北斗+智慧城市”,让城市生活更美好

10月31日是世界城市日。世界城市日是联合国首个以城市为主题的国际日,也是第一个由中国政府倡议并成功设立的国际日,出自2010年10月31日上海世博会高峰论坛上发布的《上海宣言》中的倡议。世界城市日秉承了中国2010年上海世博会“城市,让生活…

前端知识与基础应用#2

标签的分类 关于标签我们可以分为 : 单标签:img, br hr 双标签:a,h,div 按照属性可分为: 块儿标签(自己独自占一行):h1-h6, p,div 行内(内联)标签&#xff08…

【1】C语言实现顺序表

文章目录 Ⅰ 概念及结构1. 静态顺序表2. 动态顺序表 Ⅱ 基本操作实现1. 定义顺序表2. 初始化顺序表3. 销毁顺序表4. 输出顺序表5. 扩容顺序表6. 尾插法插入数据7. 头插法插入数据8. 尾删法删除数据9. 头删法删除数据10. 顺序表查找11. 在指定位置 pos 插入数据12. 删除指定位置…

【算法】动态规划之LeetCode 53.最大子数组和

目录 文章目录 **目录**📑前言1.题目描述2. 动态规划法 📑文章末尾 📑前言 本文主要是leetcode题解析,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁…

联想方案服务斩获CCF技术发明奖,助力云原生技术发展

10月27日,中国计算机学会(CCF)公布了我国计算机科技领域最具权威性的科技奖项——2023年度“CCF科技成果奖”评选结果,共有41个项目荣获2023年度CCF科技成果奖。由联想集团与上海交通大学等共同研究开发的《面向互联网服务的云原生…

【机器学习合集】模型设计之网络宽度和深度设计 ->(个人学习记录笔记)

文章目录 网络宽度和深度设计1. 什么是网络深度1.1 为什么需要更深的模型浅层学习的缺陷深度网络更好拟合特征学习更加简单 2. 基于深度的模型设计2.1 AlexNet2.2 AlexNet工程技巧2.3 VGGNet 3. 什么是网络宽度3.1 为什么需要足够的宽度 4. 基于宽度模型的设计4.1 经典模型的宽…

错误 LNK1112 模块计算机类型“x64”与目标计算机类型“X86”冲突

这个错误表明你在进行链接时,模块的计算机类型与目标计算机类型冲突。 在这里,“x64”代表64位系统,“X86”代表32位系统。 要解决这个问题,你需要确保你的所有模块(包括库文件和依赖项)都是与你的目标计…

《算法通关村—队列基本特征和实现问题解析》

《算法通关村—队列基本特征和实现问题解析》 队列的基本特征 队列(Queue)是一种常见的数据结构,具有以下基本特征: 先进先出(FIFO):队列中的元素按照它们被添加到队列的顺序排列,…

Matlab论文插图绘制模板第123期—水平正负柱状图

在之前的文章中,分享了很多Matlab柱状图的绘制模板: 进一步,再来看一种特殊的柱状图:水平正负柱状图。 先来看一下成品效果: 特别提示:本期内容『数据代码』已上传资源群中,加群的朋友请自行下…

人到中年应该怎么交朋友

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…

Doris数据库FE——FeServer

FeServer feServer new FeServer(Config.rpc_port);feServer.start();FeServer(Doris frontend thrift server)职责是负责FE和BE之间通信。如下即为初始化中关于FeServer类的构造函数和start函数的具体代码。其start函数流程和构建thrift server行为一致…

springboot网上商城购物系统

第1章 绪论 1.1背景及意义 随着社会的快速发展,计算机的影响是全面且深入的。人们生活水平的不断提高,日常生活中人们对网上商城购物系统方面的要求也在不断提高,购物的人数更是不断增加,使得网上商城购物系统的开发成为必需而且…