(十三):图

2023-11-15

1.图的基本介绍

1.1为什么要有图

前面我们学到了线性表和树,线性表局限于直接前驱和一个直接后继结点的关系。树也只能有一个直接前驱也就是父节点。当我们需要多对多关系时候,就需要图。

1.2图的举例说明

图是一种数据结构,其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为边。 结点也可以称为顶点。如图:
在这里插入图片描述

1.3图的常用概念

  • 顶点
  • 路径
    在这里插入图片描述
  • 无向图: 顶点之间的连接没有方向,比如A-B,
    即可以是 A-> B 也可以 B->A .
  • 路径: 比如从 D -> C 的路径有
  1. D->B->C
  2. D->A->B->C
  • 有向图
    在这里插入图片描述
  • 带权图
    在这里插入图片描述

2.图的表示方式

2.1临接矩阵

邻接矩阵是表示图形中顶点之间相邻关系的矩阵,对于n个顶点的图而言,矩阵是的row和col表示的是1…n个点。
在这里插入图片描述

2.2临接表

  • 邻接矩阵需要为每个顶点都分配n个边的空间,其实有很多边都是不存在,会造成空间的一定损失.
  • 邻接表的实现只关心存在的边,不关心不存在的边。因此没有空间浪费,邻接表由数组+链表组成
    在这里插入图片描述
    说明:
  • 标号为0的结点的相关联的结点为 1 2 3 4
  • 标号为1的结点的相关联结点为0 4,
  • 标号为2的结点相关联的结点为 0 4 5

2.3入门案例

要求: 代码实现如下图结构.

在这里插入图片描述
在这里插入图片描述
思路分析 (1) 存储顶点String 使用 ArrayList (2) 保存矩阵 int[][] edges
代码如下:

public class Graph {
    private ArrayList<String> vertexList;//存储顶点的集合
    private int[][] edges;//存储图对应的临结矩阵
    private int numOfEdges;//表示边的数目
    //定义一个boolean[]记录结点是否被直接访问
    private boolean[] isVisited;
       //显示图对应的矩阵
    public void showGraph(){
        for (int[] link:edges){
            System.out.println(Arrays.toString(link));
        }
    }
    //构造器
    public Graph(int n){
        //初始化矩阵和vertexList
        edges=new int[n][n];
        vertexList=new ArrayList<>(n);
        numOfEdges=0;//因为不知道多少边嘛

    }
    //途中常用的方法
    //返回结点的个数
    public int getNumOfVertex(){
        return vertexList.size();
    }
    //得到边的个数
    public int getNumOfEdges(){
        return numOfEdges;
    }
    //返回结点i(下标)对应的数据
    public String getValueByIndex(int i){
        return vertexList.get(i);
    }
    //返回v1和v2的权值
    public int getWeight(int v1,int v2){
        return edges[v1][v2];
    }
    //插入结点
    public void insertVertext(String vertex){
        vertexList.add(vertex);
    }
    //添加边
    /**
     *
     * @param v1 表示点的下标即第几个顶点
     * @param v2 第二个顶点对应的下标
     * @param weight 表示
     */
    public void insertEdge(int v1,int v2,int weight){
        edges[v1][v2]=weight;
        edges[v2][v1]=weight;
        numOfEdges++;

    }
    }

3.图的遍历

所谓图的遍历,即是对结点的访问。一个图有那么多个结点,如何遍历这些结点,需要特定策略,一般有两种访问策略: (1)深度优先遍历 (2)广度优先遍历

3.1深度优先遍历

3.1.1深度优先遍历思想

图的深度优先搜索(Depth First Search) 。
深度优先遍历,从初始访问结点出发,初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接结点, 可以这样理解:每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。
我们可以看到,这样的访问策略是优先往纵向挖掘深入,而不是对一个结点的所有邻接结点进行横向访问。
显然,深度优先搜索是一个递归的过程

3.1.2深度优先遍历算法步骤

1、访问初始结点v,并标记结点v为已访问。
2、查找结点v的第一个邻接结点w。
3、若w存在,则继续执行4,如果w不存在,则回到第1步,将从v的下一个结点继续。
4、若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行步骤123)。
5、查找结点v的w邻接结点的下一个邻接结点,转到步骤3。

3.1.3代码

 //对dfs进行一个重载,遍历我们所有的节点,并进行dfs
    public void dfs(){
        isVisited=new boolean[vertexList.size()];
        //遍历所有的节点进行dfs
        for (int i=0;i<getNumOfVertex();i++){
            if (!isVisited[i]){
                dfs(isVisited,i);
            }
        }
    }
 //深度优先遍历算法
    public void dfs(boolean[] isVisited,int i){
        //首先访问该节点,就是输出
        System.out.println(getValueByIndex(i)+"->");
        //将该节点设置为已经访问过
        isVisited[i]=true;
        //查找节点i的第一个邻接节点w
        int w=getFirstNeighbor(i);
        while(w!=-1){//说明有邻接节点
            if (!isVisited[w]){
                dfs(isVisited,w);
            }
            //如果w已经被访问过了
            w=getNextNeighbor(i,w);
        }
    }
    
    /**
     *
     * @param index 如果存在就返回对应的下标否则就是-1
     * @return
     */
    public int getFirstNeighbor(int index){
        for (int j=0;j<vertexList.size();j++){
            if (edges[index][j]>0){
                return j;
            }
        }
        return -1;

    }
    //根据前一个邻接节点的下标来获取下一个邻接节点
    public int getNextNeighbor(int v1,int v2){
       for (int j=v2+1;j<vertexList.size();j++){
           if (edges[v1][j]>0){
               return j;
           }
       }
       return -1;
    }

3.2广度优先遍历

3.2.1广度优先遍历基本思想

图的广度优先搜索(Broad First Search) 。
类似于一个分层搜索的过程,广度优先遍历需要使用一个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点。

3.2.2广度优先遍历的算法步骤

1.访问初始结点v并标记结点v为已访问。
2.结点v入队列
3.当队列非空时,继续执行,否则算法结束。
4.出队列,取得队头结点u。
5.查找结点u的第一个邻接结点w。
6.若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
6.1 若结点w尚未被访问,则访问结点w并标记为已访问。
6.2 结点w入队列
6.3 查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。

3.2.3代码

  //对一个节点进行广度优先遍历的方法
    private void bfs(boolean[] isVisited,int i){
        int u;//表示队列的头结点对应的下标
        int w;//邻接节点
        //队列,记录结点访问的顺序
        LinkedList queue=new LinkedList();
        //访问结点
        System.out.println(getValueByIndex(i)+"=>");
        //标记为已访问
        isVisited[i]=true;
        //将结点加入队列
        queue.add(i);
        while (!queue.isEmpty()){
            //取出队列的头结点下标
            u=(Integer) queue.removeFirst();
            //得到第一个邻接点的下标w
            w=getFirstNeighbor(u);
            while (w!=-1){//找到了
                //是否访问过
                if (!isVisited[i]){
                    System.out.println(getValueByIndex(i)+"=>");
                    //标记已经访问
                    isVisited[w]=true;
                    //入队
                    queue.addLast(w);
                }
                //加入已经访问了应该找以u为前驱找w后面的下一个连接点
                w=getNextNeighbor(u,w);//体现出了广度优先

            }
        }



    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(十三):图 的相关文章

  • Java中ArrayList的交集和并集

    有什么方法可以做到这一点吗 我正在寻找 但没有找到 另一个问题 我需要这些方法 以便我可以过滤文件 有些是AND过滤器 有些是OR过滤器 就像集合论中的那样 所以我需要根据所有文件和保存这些文件的联合 相交 ArrayList 进行过滤 我
  • Spring应用中Eureka健康检查的问题

    我正在开发一个基于 Spring 的应用程序 其中包含多个微服务 我的一个微服务充当尤里卡服务器 到目前为止一切正常 在我所有其他微服务中 用 EnableEurekaClient 我想启用这样的健康检查 应用程序 yml eureka c
  • org.apache.hadoop.security.AccessControlException:客户端无法通过以下方式进行身份验证:[TOKEN,KERBEROS] 问题

    我正在使用 java 客户端通过 Kerberos 身份验证安全访问 HDFS 我尝试打字klist在服务器上 它显示已经存在的有效票证 我收到的异常是客户端无法通过以下方式进行身份验证 TOKEN KERBEROS 帮助将不胜感激 这是一
  • 过滤两次 Lambda Java

    我有一个清单如下 1 2 3 4 5 6 7 和 预期结果必须是 1 2 3 4 5 6 7 我知道怎么做才能到7点 我的结果 1 2 3 4 5 6 我也想知道如何输入 7 我添加了i gt i objList size 1到我的过滤器
  • 在 Jar 文件中运行 ANT build.xml 文件

    我需要使用存储在 jar 文件中的 build xml 文件运行 ANT 构建 该 jar 文件在类路径中可用 是否可以在不分解 jar 文件并将 build xml 保存到本地目录的情况下做到这一点 如果是的话我该怎么办呢 Update
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 没有 Spring 的自定义 Prometheus 指标

    我需要为 Web 应用程序提供自定义指标 问题是我不能使用 Spring 但我必须使用 jax rs 端点 要求非常简单 想象一下 您有一个包含键值对的映射 其中键是指标名称 值是一个简单的整数 它是一个计数器 代码会是这样的 public
  • java.lang.IllegalStateException:提交响应后无法调用 sendRedirect()

    这两天我一直在尝试找出问题所在 我在这里读到我应该在代码中添加一个返回 我做到了 但我仍然得到 java lang IllegalStateException Cannot call sendRedirect after the respo
  • 无法创建请求的服务[org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]-MySQL

    我是 Hibernate 的新手 我目前正在使用 Spring boot 框架并尝试通过 hibernate 创建数据库表 我知道以前也问过同样的问题 但我似乎无法根据我的环境找出如何修复错误 休眠配置文件
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • 帮助将图像从 Servlet 获取到 JSP 页面 [重复]

    这个问题在这里已经有答案了 我目前必须生成一个显示字符串文本的图像 我需要在 Servlet 上制作此图像 然后以某种方式将图像传递到 JSP 页面 以便它可以显示它 我试图避免保存图像 而是以某种方式将图像流式传输到 JSP 自从我开始寻
  • 在我的 Spring Boot 示例中无法打开版本 3 中的 Swagger UI

    我在 Spring Boot 示例中打开 swagger ui 时遇到问题 当我访问 localhost 8080 swagger ui 或 localhost 8080 root api name swagger ui 时出现这种错误 S
  • 尝试将 Web 服务部署到 TomEE 时出现“找不到...的 appInfo”

    我有一个非常简单的项目 用于培训目的 它是一个 RESTful Web 服务 我使用 js css 和 html 创建了一个客户端 我正在尝试将该服务部署到 TomEE 这是我尝试部署时遇到的错误 我在这里做错了什么 刚刚遇到这个问题 我曾
  • 如何使用 jUnit 将测试用例添加到套件中?

    我有 2 个测试类 都扩展了TestCase 每个类都包含一堆针对我的程序运行的单独测试 如何将这两个类 以及它们拥有的所有测试 作为同一套件的一部分执行 我正在使用 jUnit 4 8 在 jUnit4 中你有这样的东西 RunWith
  • Cucumber 0.4.3 (cuke4duke) 与 java + maven gem 问题

    我最近开始为 Cucumber 安装一个示例项目 并尝试使用 maven java 运行它 我遵循了这个指南 http www goodercode com wp using cucumber tests with maven and ja
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • 使用反射覆盖最终静态字段是否有限制?

    在我的一些单元测试中 我在最终静态字段上的反射中遇到了奇怪的行为 下面是说明我的问题的示例 我有一个基本的 Singleton 类 其中包含一个 Integer public class BasicHolder private static
  • 使用 svn 1.8.x、subclise 1.10 的 m2e-subclipse 连接器在哪里?

    我读到 m2e 的生产商已经停止生产 svn 1 7 以外的任何版本的 m2e 连接器 Tigris 显然已经填补了维护 m2e subclipse 连接器的空缺 Q1 我的问题是 使用 svn 1 8 x 的 eclipse 更新 url
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类

随机推荐

  • 数据的探索性分析

    探索一下 数据分析的起点 数据分类 一 描述性分析 整理数据 定义 主要作用 可视化技术 定义 主要作用 常用方法 二 相关性分析 分析数据 定义 主要作用 相关性分类 相关性测定 三 假设检验 分析数据 定义 作用 步骤 相对理论 常见的
  • 对某底层硬件模块编写底层程序的主要步骤及经验

    一 禁止硬件模块运行 配置好相关寄存器 这里的硬件模块是指那些CPU发一些指令后就能独立工作的模块 二 置位硬件模块控制寄存器的使能位 使能硬件模块 三 明确功能 搞清楚哪些工作是由硬件来做的 哪些该由软件来执行 四 当由硬件模块来做的工作
  • NAPI(New API)的一些浅见

    NAPI真的是kernel开发者词穷想的名字吧 你看看kernel里面各种名字 不知道为啥就不能起个好听点的 言归正传 wiki https en wikipedia org wiki New API 给出的解释是NAPI是一种用于网络设备
  • PyTorch基础练习-task4(用PyTorch实现多层网络)

    PyTorch基础练习 task4 一 引入模块 读取数据 二 构建网络模型 三 损失函数与优化器 四 开始训练模型 五 模型预测结果评估 一 引入模块 读取数据 从sklearn包中直接加载糖料病数据集 二 构建网络模型 三 损失函数与优
  • 【uniapp】uni-datetime-picker组件修改分钟选项为每15分钟的时间间隔 (0 15 30 45)

    一开始没打算写这个功能实现 毕竟不是自己写的组件 而是去改uniapp的扩展组件 但是确实在修改的时候上网查 没有查到关于这种功能实现的准确信息 所以在功能完成后也写一份 希望能给需要的人一个参考 做项目遇到一个关于时间预约的功能 最开始给
  • JetBrains全家桶(IDEA、Pycharm等各个产品)在国内高速下载地址

    JetBrains产品在国内有CDN下载通道 下面给出各个产品的下载链接 在某些情况下 官网无法访问 可以使用下面的链接直接下载 只需要照模样修改后缀名和年份版本号即可 操作系统后缀 Win exe 安装版 Win win zip 解压版
  • MySQL按条件删除指定数据(删除整行)

    delete from tb where update tb set string helloworld where name louyujing and type 1
  • Frame,Panel和三种布局管理器

    窗体Frame 举例 单个窗体 frame窗体存在在内存中 看不见 Frame frame new Frame 我的JAVA窗体 设置窗体的可见性 frame setVisible true 设置窗体的尺寸 frame setSize 40
  • 基于python、keras的鸟类分类识别——深度学习举一反三案例

    界面用tkinter来制作 这是一个深度学习的练习项目 目前是1 0版本以后会逐步完善
  • STM32F1和F4的GPIO口模式设置以及对应关系

    目录 GPIO端口8种模式 STM32F103的GPIO配置 STM32F407的GPIO配置 F4的GPIO的8种模式配置 GPIO端口8种模式 输入浮空 输入上拉 输入下拉 模拟输入 开漏输出 推挽输出 推挽复用功能 开漏复用功能 查看
  • Java十万字笔记(带索引)

    目录 Java类与对象学习学习路线 名词的别称 权限修饰符 访问控制权限 属性默认值 类与对象定义 对象的定义和使用 成员属性的权限 构造方法 区别 深拷贝和浅拷贝 成员属性封装 构造重载实例 为何要封装 引用传递 浅拷贝 与垃圾分析 匿名
  • Vue使用AMapUI,JSAPI2.0拖拽定位无法获取定位问题

    在Amap 高德地图 自2021年12月02日升级 升级之后所申请的 key 必须配备安全密钥 jscode 一起使用 如果这里没有没有配备安全密钥的话 会导致INVALID USER SCODE错误 这个问题 需要在加载地图之前配置安全秘
  • Hibernate学习笔记 开始学习

    Hibernate简介 Hibernate是一个优秀的对象关系映射 ORM 框架 如果你有使用纯JDBC写过一个类似博客之类的小程序的话 就知道编写JDBC语句以及转化结果集为Java对象是一件非常繁复的事情 利用Hibernate这样的O
  • 基于神经网络实现手写数字识别(matlab)

    实验目的 在matlab平台上 采用神经网络实现手写数字识别 在实验过程中 1 初步探讨数据集预处理的作用 2 增加对神经网络的理解 探讨隐含层层数 节点数和训练步长对识别成功率的影响 找到较佳的参数 3 应用交叉验证法评估训练模型的优劣
  • Java-基于SSM+JSP的二手手机回收管理系统

    项目背景 21世纪的今天 随着社会的不断发展与进步 人们对于信息科学化的认识 已由低层次向高层次发展 由原来的感性认识向理性认识提高 管理工作的重要性已逐渐被人们所认识 科学化的管理 使信息存储达到准确 快速 完善 并能提高工作管理效率 促
  • 关闭MFC对话框时删除自身

    1 在DLG类中添加成员函数 BOOL DeleteSelft 代码如下 class CDelSelfDlg public CDialog Construction public CDelSelfDlg CWnd pParent NULL
  • Vscode——报错解决:Import “torch“ could not be resolved

    一 原因 当前解释器环境中 没安装torch库 二 解决办法 前提 已经安装PyTorch环境 1 键盘上按快捷键 Ctrl shift P 2 输入 Python Select Interpreter 3 选择PyTorch解释器
  • active directory域服务

    active directory域服务 一 Windows 网络环境 工作组workgroup 域 二 windows域 1 集中管理 2 分域控制器和成员服务器 3 账户保存在域当中 文件名为 ntds dit 4 账户可在整个域当中登陆
  • 直播预告

    12月26日 RTSCon2021开发者沙龙将在线上举办 拍乐云Pano受邀出席 服务端专家沈伟锋将在活动中带来关于 拍乐云融合语音通话技术实践 的主题演讲 RTSCon的前身是FreeSWITCH开发者沙龙 而RTS的全称是Real Ti
  • (十三):图

    1 图的基本介绍 1 1为什么要有图 前面我们学到了线性表和树 线性表局限于直接前驱和一个直接后继结点的关系 树也只能有一个直接前驱也就是父节点 当我们需要多对多关系时候 就需要图 1 2图的举例说明 图是一种数据结构 其中结点可以具有零个