【软考】图的遍历

news2024/11/19 8:32:47

目录

        • 1. 概念
        • 2. 深度优先搜索
          • 2.1 说明
          • 2.2 步骤
        • 3. 深度优先搜索例子
          • 3.1 无向图
          • 3.2 代码示例
          • 3.3 结果示例
          • 3.4 过程
        • 4. 广度优先搜索
          • 4.1 说明
          • 4.2 步骤
        • 5. 广度优先搜索例子
          • 5.1 无向图
          • 5.2 代码示例
          • 5.3 结果示例
          • 5.4 过程
          • 5.5 例题
            • 5.5.1 题目1

1. 概念
  • 1.图的遍历是指从某个顶点出发,沿着某条搜索路径对图中的所有顶点进行访问且只访问一次的过程
  • 2.图的遍历算法是求解图的连通性问题、拓扑排序及求关键路径等算法的基础
  • 3.图的遍历比树的遍历复杂
  • 4.图的任一个结点都可能与其余顶点相邻接,所以在访问了某个顶点之后,可能沿着某路径又回到该结点上,为了避免对顶点进行重复访问,在图的遍历过程中必须记下每个已访问过的顶点
  • 5.深度优先搜索和广度优先搜索是两种遍历图的基本方法
2. 深度优先搜索
2.1 说明
  • 1.Depth First Search, DFS
  • 2.类似于树的先根比遍历,在第一次经过一个顶点时就进行访问访问操作
  • 3.深度优先遍历图的过程实质上是对某个顶点查找其邻接点的过程,其耗费的时间取决于所采用的存储结构
  • 4.当图用邻接矩阵表示时,查找所有顶点的邻接点所需时间为 O(n)。
  • 5.若以邻接表作为图的存储结构,则需要 O(e)的时间复杂度查找所有顶点的邻接点。因此,当以邻接表作为存储结构时,深度优先搜索遍历图的时间复杂度为 O(n+e)。
2.2 步骤
  • 1.设置搜索指针p,使p指向顶点v
  • 2.访问p所指顶点,并使p指向与其相邻接的且尚未被访问过的顶点
  • 3.若p所指顶点存在,则重复步骤2,否则执行步骤4
  • 4.沿着刚才访问的次序和方向回溯到一个尚有邻接顶点且未被访问过的顶点,并使p指向这个未被访问的顶点,然后重复步骤2,直到所有的顶点均被访问为止
  • 5.该算法的特点是尽可能先对纵深方向搜索,因此可以得到其递归遍历算法
  • 6.
3. 深度优先搜索例子
3.1 无向图
3.2 代码示例
package com.learning.algorithm.search.graph;

import java.util.*;

public class Graph {
    // 顶点的数量
    private int number;
    // 邻接列表
    private LinkedList<Integer>[] adjacency;

    public Graph(int number) {
        this.number = number;
        adjacency = new LinkedList[number];
        for (int i = 0; i< number; ++i) {
            adjacency[i] = new LinkedList();
        }
    }

    // 向图中添加边
    public void addEdge(int v, int w) {
        adjacency[v].add(w);
    }

    // 从v可达顶点的深度优先搜索
    public void depthFirstSearch(int v, boolean visited[]) {
        // 将当前节点标记为已访问并打印
        visited[v] = true;
        System.out.print(v+" ");

        // 对与此顶点相邻的所有顶点重复搜索
        Iterator<Integer> i = adjacency[v].listIterator();
        while (i.hasNext()) {
            int n = i.next();
            if (!visited[n]) {
                depthFirstSearch(n, visited);
            }
        }
    }

    public static void main(String args[]) {
        Graph g = new Graph(4);

        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);

        // 从顶点2开始
        boolean[] visited = new boolean[g.number];
        g.depthFirstSearch(2, visited);
    }
}
3.3 结果示例

在这里插入图片描述

3.4 过程
  • 1.从顶点2开始搜索,将顶点2标记为已访问
  • 2.获取顶点2可到达的顶点0和顶点3
  • 3.判断顶点0是否已访问,没有访问,则从顶点0开始搜索,将顶点0标记为已访问(从第2点过来的)
  • 4.获取顶点0可到达的顶点1和顶点2(从第3点过来的)
  • 5.判断顶点1是否已访问,没有访问,则从顶点1开始搜索,将顶点1标记为已访问(从第4点过来的)
  • 6.获取顶点1可到达的顶点0和顶点2(从第5点过来的)
  • 7.判断顶点0是否已访问,顶点0已访问(从第6点过来的)
  • 8.判断顶点2是否已访问,顶点2已访问(从第6点过来的)
  • 9.判断顶点2是否已访问,顶点2已访问(从第4点过来的)
  • 10.判断顶点3是否已访问,没有访问,则从顶点3开始搜索,将顶点3标记为已访问(从第2点过来的)
  • 11.获取顶点3可到达的顶点2和顶点3(从第10点过来的)
  • 12.判断顶点2是否已访问,顶点2已访问(从第11点过来的)
  • 13.判断顶点3是否已访问,顶点3已访问(从第11点过来的)
4. 广度优先搜索
4.1 说明
  • 1.Breadth First Search, BFS
  • 2.广度优先遍历图的特点是尽可能先进行横向搜索,即最先访问的顶点的邻接点也先被访问。为此引入队列来保存已访问过的顶点序列,即每当一个顶点被访问后,就将其放入队列中,当队头顶点出队时,就访问其未被访问的邻接点并令这些邻接顶点入队
  • 3.在广度优先遍历算法中,每个顶点最多尽进一次队列
  • 4.遍历图的过程实质上是通过边或弧找邻接点的过程,因此广度优先搜索遍历图和深度优先搜索遍历图的运算时间复杂度相同,其不同之处仅仅在于对顶点访问的次序不同
4.2 步骤
  • 1.图的广度优先搜索方法为:从图中的某个顶点v出发,在访问了v之后依次访问v的各个未被访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直到图中所有已被访问的顶点的邻接点都被访问到。若此时还有未被访问的点,则另选图中的一个未被访问的顶点作为起点,重复上述过程,直到图中所有的顶点都被访问到为止
5. 广度优先搜索例子
5.1 无向图
5.2 代码示例
package com.learning.algorithm.search.graph.breadth_first_search;

import java.util.*;
  
public class Graph {
    private int number;
    private LinkedList<Integer>[] adjacency;
  
    public Graph(int number) {
        this.number = number;
        adjacency = new LinkedList[number];
        for (int i = 0; i < number; ++i) {
            adjacency[i] = new LinkedList();
        }
    }

    public void addEdge(int src, int dest) {
        adjacency[src].add(dest);
        // 因为是无向图,所以需要添加反向边
        adjacency[dest].add(src);
    }

    public void breadthFirstSearch(int v) {
        boolean visited[] = new boolean[number];
        Queue<Integer> queue = new LinkedList<>();

        visited[v] = true;
        queue.add(v);

        while (!queue.isEmpty()) {
            int currentVertex = queue.poll();
            System.out.print(currentVertex + " "); // 访问当前节点

            Iterator<Integer> i = adjacency[currentVertex].listIterator();
            while (i.hasNext()) {
                int adjacentVertex = i.next();
                if (!visited[adjacentVertex]) {
                    visited[adjacentVertex] = true;
                    queue.add(adjacentVertex);
                }
            }
        }
    }
  
    public static void main(String args[]) {  
        Graph g = new Graph(7);

        g.addEdge(0, 1);
        g.addEdge(0, 4);
        g.addEdge(1, 2);
        g.addEdge(1, 3);
        g.addEdge(1, 4);
        g.addEdge(2, 3);
        g.addEdge(3, 4);

        g.breadthFirstSearch(0);
    }
}
5.3 结果示例

在这里插入图片描述

5.4 过程
  • 1.从图中的顶点0出发,将顶点0标记为已访问,将顶点0放入队列
  • 2.如果队列不为空,拿出队首顶点0,打印顶点0,获取顶点0可到达的顶点,即顶点1和顶点4
  • 3.顶点1没有被访问,将顶点1标记为已访问,将顶点1放入队列
  • 4.顶点4没有被访问,将顶点4标记为已访问,将顶点4放入队列
  • 5.此时队列不为空,拿出队首顶点1,打印顶点1,获取顶点1可到达的顶点,即顶点0,顶点2,顶点3和顶点4
  • 6.顶点0已经被访问
  • 7.顶点2没有被访问,将顶点2标记为已访问,将顶点2放入队列
  • 8.顶点3没有被访问,将顶点3标记为已访问,将顶点3放入队列
  • 9.顶点4已经被访问
  • 10.此时队列不为空,拿出队首顶点4,打印顶点4,获取顶点4可到达的顶点,即顶点0,顶点1和顶点3
  • 11.顶点0已经被访问
  • 12.顶点1已经被访问
  • 13.顶点3已经被访问
  • 14.此时队列不为空,拿出队首顶点2,打印顶点2,获取顶点2可到达的顶点,即顶点1和顶点3
  • 15.顶点1已经被访问
  • 16.顶点3已经被访问
  • 15.此时队列不为空,拿出队首顶点3,打印顶点3,获取顶点3可到达的顶点,即顶点1,顶点2和顶点4
  • 16.顶点1已经被访问
  • 17.顶点2已经被访问
  • 18.顶点4已经被访问
  • 19.此时队列为空结束

从图中的某个顶点v出发,在访问了v之后依次访问v的各个未被访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直到图中所有已被访问的顶点的邻接点都被访问到。若此时还有未被访问的点,则另选图中的一个未被访问的顶点作为起点,重复上述过程,直到图中所有的顶点都被访问到为止

5.5 例题
5.5.1 题目1
  • 1.题目内容
例题1:图G的邻接矩阵如下图所示(顶点依次表示为v0、v1、v2、v3、v4、v5),G是( 1 )。
对G进行广度优先遍历(从v0开始),可能的遍历序列为( 2 )。
1. 	A.无向图 B.有向图 C.完全图 D.强连通图

2. 	A.v0、v1、v2、v3、v4、v5
	B.v0、v2、v4、v5、v1、v3
	C.v0、v1、v3、v5、v2、v4
	D.v0、v2、v4、v3、v5、v1
  • 2.题目解析
1.由图可以看出,v0可以到达v1和v2,v1可以到达v3,v2可以到达v1和v3,v3可以到达v5,v4可以到达v5
2.部分是单向的因此不是无向图,而是有向图,选B
3.不是完全图(完全图是一个简单的无向图,其中每对不同的顶点之间都恰有一条边相连)
4.不是强连通图(任意两个顶点之间都存在至少一条从一个顶点到另一个顶点的路径,同时也存在至少一条反向的路径)

5.v0可以到v1和v2,则v0、v1、v2,因此选A

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

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

相关文章

递增三元组 刷题笔记

题意为 若存在 a中的数小于b中的数&#xff0c;b中的数小于c中的数 则该数算一种方案 思路 暴力模拟优化 两层循环遍历即可 从b到c的过程我们发现 第三层并不需要循环 直接加上 大于b的数量即可 那么第一层和第三层是对称的 我们有没有可能再去掉一层循环 只做一次遍历 …

Spring boot2.7整合jetcache 本地linkedhashmap缓存方案

好 上文 Spring boot2.7整合jetcache 远程redis缓存方案 我们讲完了 远程实现方案 本文 我们来说说 本地 jetcache解决方案 首先是 application.yml 在jetcache下加上 local:default:type: linkedhashmapkeyConvertor: fastjson我们技术用的 本地缓存 linkedhashmap 这里 我们…

netty草图笔记

学一遍根本记不住&#xff0c;那就再学一遍 public static void test_nettyFuture() {NioEventLoopGroup group new NioEventLoopGroup();log.info("开始提交任务");Future<String> future group.next().submit(() -> {log.info("执行异步任…

DualSPHysics使用FlowTool工具进行后处理,定义的粒子全在domains外,解决办法

可以知道DualSPHysics官方给了后处理工具使用的示例&#xff0c;如下就是官方给的案例&#xff0c;使用FlowTool工具可以计算出在两个实体domain内的粒子数。 然而我自己也定义了2个domains&#xff0c;但是计算出来Tank1和Tank2里边的粒子数一直是空的&#xff0c;粒子全部在…

微服务系列(一)springcloudAlibaba之Nacos注册和配置中心及openFeign远程调用

一&#xff0c;认识微服务 我们先看看开发大型项目采用单体架构存在哪些问题&#xff0c;而微服务架构又是如何解决这些问题的。 1.1 单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;整个项目中所有功能模块都在一个工程中开发&#xff1b;项目部署…

数学建模【时间序列】

一、时间序列简介 时间序列也称动态序列&#xff0c;是指将某种现象的指标数值按照时间顺序排列而成的数值序列。时间序列分析大致可分成三大部分&#xff0c;分别是描述过去、分析规律和预测未来&#xff0c;本篇将主要介绍时间序列分析中常用的三种模型&#xff1a;季节分解…

第3集《天台教观纲宗》

乙二、约观行释 诸位法师慈悲&#xff01;陈会长慈悲&#xff01;诸位菩萨&#xff01;阿弥陀佛&#xff01; 请大家打开讲义第六页。我们看到乙二、约观行释。这一科是讲到天台教观的修学宗旨。 我们前面讲到&#xff0c;天台教观整个建立的过程&#xff0c;它是先有观法&a…

AHU 汇编 实验一

一、实验名称&#xff1a;实验1 实验1 用Debug命令查看寄存器和内存中的内容 实验目的:求掌握使用Debug命令查看寄存器和内存的方法。 通过第2章两个简单实例认识汇编语言程序&#xff0c;初步了解程序格式&#xff1b;段定义&#xff1b;标号&#xff1b;DOS系统功能&#xf…

017-$route、$router

$route、$router 1、$route2、$router 1、$route $route 对象表示当前的路由信息&#xff0c;包含了当前 URL 解析得到的信息。包含当前的路径&#xff0c;参数&#xff0c;query对象等。 使用场景&#xff1a; 获取路由传参&#xff1a;this.$route.query、this.$route.par…

Linux-socket套接字

前言 在当今数字化时代&#xff0c;网络通信作为连接世界的桥梁&#xff0c;成为计算机科学领域中至关重要的一部分。理解网络编程是每一位程序员必备的技能之一&#xff0c;而掌握套接字编程则是深入了解网络通信的关键。本博客将深入讨论套接字编程中的基本概念、常见API以及…

C++指针(五)完结篇

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 前言 相关文章&#xff1a;C指针&#xff08;一&#xff09;、C指针&#xff08;二&#xff09;、C指针&#xff08;三&#xff09;、C指针&#xff08;四&#xff09;万字图文详解&#xff01; 本篇博客是介…

Independent Variable Dependent Variable

自变量&#xff08;Independent Variable&#xff09; -----------> 因变量&#xff08;Dependent Variable&#xff09; 数据 ----------------------------------------------结果&#xff0c;报告等等

面试宝典-【redis】

目录 1.什么是缓存穿透 ? 怎么解决 ? 2.什么是布隆过滤器 3.什么是缓存击穿 ? 怎么解决 ? 4.什么是缓存雪崩 ? 怎么解决 ? 5.redis做为缓存&#xff0c;mysql数据如何与redis进行同步?(双写) 6.排他锁是如何保证读写、读读互斥的呢&#xff1f; 7.你听说过延…

3月10日

微机原理 1M1000k 1000/5200 200 NMI INTR 主 从 从 8-288 ZF0 100H MOVBX,[DI] 0AA55 基址 寄存器 ENDS SP 指示型和指令行的区别 指令型的语句是可执行的最终产生机器码会上机运行需要CPU去运行 指示型语句是指示如何汇编 数据定义 DB DW 符号定义 EQU 取值 TYPE OF…

Vite:下一代前端开发与构建工具

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

基于鹦鹉优化算法(Parrot optimizer,PO)的无人机三维路径规划(提供MATLAB代码)

一、无人机路径规划模型介绍 无人机三维路径规划是指在三维空间中为无人机规划一条合理的飞行路径&#xff0c;使其能够安全、高效地完成任务。路径规划是无人机自主飞行的关键技术之一&#xff0c;它可以通过算法和模型来确定无人机的航迹&#xff0c;以避开障碍物、优化飞行…

鲜为人知的闰年判定大坑

【题目描述】 输入年份&#xff0c;判断是否为闰年。如果是&#xff0c;则输出yes&#xff0c;否则输出no。 提示&#xff1a;简单地判断除以4的余数是不够的。 【题目来源】 刘汝佳《算法竞赛入门经典 第2版》习题1-7 年份&#xff08;year&#xff09; 【解析】 一、闰…

多线程多进程处理服务器并发(多进程处理如何解决僵死进程)

目录 1.可循环发送数据的代码 2.改成循环之后每次发现只能处理一个客户端 3.服务器端处理并发问题 3.1 思路 3.2 利用多线程实现并发 ​编辑 3.3 利用多进程实现并发 3.3.1 多进程并发产生的僵死进程问题 ​3.3.2 解决僵死进程问题 1.可循环发送数据的代码 服务器代…

vue 在什么情况下在数据发生改变的时候不会触发视图更新

在 Vue 中&#xff0c;通常数据发生变化时&#xff0c;视图会自动更新。但是&#xff0c;有几种情况可能导致数据变化不会触发视图更新&#xff1a; 1.对象属性的添加或删除&#xff1a; Vue 无法检测到对象属性的添加或删除。因为 Vue 在初始化实例时对属性执行了 getter/se…

【教学类-34-09】20240310华文彩云学号拼图(3*3格子浅灰底图 深灰拼图块)(AI对话大师)

作品展示 背景需求&#xff1a; 制作了两位数的学号3*3格子&#xff0c; 【教学类-34-05】20230523拼图&#xff08;数字学号0X-长方块拼图-双色深灰浅灰&#xff09;3*3格子&#xff08;中班主题《个别化拼图》偏艺术-美术&#xff09;_灰底白色方块数字怎么制作-CSDN博客文…