引入

树的遍历方式可分为深搜和广搜,这同样适用于图,不过有些地方会有出入。

树的节点结构从根到叶子节点都是1:n,到叶子节点后就没有了。而对于图来说,如果到了最底下的节点,它可能除了连接已经记录过的上层节点,还连接着上一层的其他未被记录的节点(比如下图的V8),那对于第三层的节点(V4、V5)来说,再往下顺延就成了2:1(n:m)了。
在这里插入图片描述

图的深搜

与树的深搜类似,一直沿着一个方向走到底就是深搜。从V1遍历到V8之后,因为V8连接着两个节点,遍历节点时如何准确遍历到还未被访问的节点,这时候可以通过数组来做标记(标记已遍历的),防止重复遍历。
之后就精准的遍历到了V5,那下一步应该怎么办?对于V5来说它连接了V8和V2,而此时两者都已经访问过了。与树的遍历相似,访问到底了就回退到根节点继续遍历另外一边,直到所有节点都被标记。

图的广搜

深搜和广搜都需要用数组存储标记信息防止重复便利,除此之外:
在之前的二叉树的广搜和深搜这篇文章里利用队列来实现记忆功能从而完成广搜的方法同样适用于图的广搜,这里不再附图了,想更直观的了解过程可以点进去看一下。

遍历过V1之后就将V1连接的的下一层节点都入队(先左后右,先进先出),之后将入队的节点逐个出队,每出队一个节点就将此节点连接的下一层节点都入队,直到所有节点出队。
需要注意的是广搜中标记的是已进入队列的节点,不是访问过的节点,防止重复入队。

在写代码之前先到上一篇回顾一下图的邻接矩阵的存储特点:
示意图, 邻接矩阵!本篇没有邻接表的代码。

头文件

在代码中,1E4 是科学计数法的表示形式,它表示的是 10^4 ,也就是十进制的 10000 。
在图的邻接矩阵表示中,常常会用一个很大的值(比如这里的 1E4 )来表示两个顶点之间没有边相连(即不可达),这类似于无穷大的概念,在后续涉及到图的路径、权重等相关算法(如最短路径算法)时,方便进行计算和判断。

#pragma once
#define INF 1E4
#define MaxNodeNum 20typedef struct {int no;       //顶点编号char* show;   //显示指向的数组的对应内容(如A、B)
}MatrixVertex;    //矩阵顶点typedef int MatrixEdge; 
//图的邻接矩阵表示法
typedef struct {                MatrixVertex vex[MaxNodeNum];  //顶点集int nodeNum;                   //约束实际的顶点个数MatrixEdge edge[MaxNodeNum][MaxNodeNum]; //边集int edgeNum;                   //边的数量int directed;                  //是否有向
}MGraph; //表示邻接矩阵(邻接图的缩写)void initMGraph(MGraph* graph, char* names[], int num, int directed, int edgeValue);
void addMGraphEdge(MGraph* graph, int x, int y, int w);
void visitMGraphNode(MatrixVertex* node);
void initVisited();void DFS_MGraph(MGraph* graph, int v);
void BFS_MGraph(MGraph* graph, int v);

功能实现

判断是否有边
static int isEdge(int weight) {if (weight > 0 && weight < INF) {return 1;}return 0;
}
初始化
void initMGraph(MGraph* graph, const char* names[], int num, int ditected, int edgeValue) {graph->directed = ditected;graph->nodeNum = num;graph->edgeNum = 0;   //初始边的权值为0,代表没有边memset(graph->vex, 0, sizeof(graph->vex));memset(graph->edge, 0, sizeof(MatrixEdge)*MaxNodeNum*MaxNodeNum);for (int i = 0; i < num; ++i) {//顶点(一维数组)填充graph->vex[i].no = i;graph->vex[i].show =(char*) names[i];for (int j = 0; j < num; ++j) {//边(矩阵)的填充graph->edge[i][j] = edgeValue; }}
}
添加边
void addMGraphEdge(MGraph* graph, int x, int y, int w) {if (x<0 || x>graph->nodeNum) {return;}if (y<0 || y>graph->nodeNum) {return;}if (!isEdge(graph->edge[x][y])) { //如果没有边再执行graph->edge[x][y] = w;if (graph->directed == 0) {  //如果是无向则同时标记对向路径的权值graph->edge[y][x] = w; //矩阵的转置}graph->edgeNum++;  //同时更新路径数目}
}
访问当前顶点
void visitMGraphNode(MatrixVertex* node) {printf("\t%s", node->show);    //访问当前顶点的展示内容(如A、B)
}
标记与初始化标记
static int MGraphVisited[MaxNodeNum]; //用来标记已遍历的顶点void initVisited() {    //初始化已标记的顶点,防止多次遍历时受干扰memset(MGraphVisited, 0, sizeof(MGraphVisited));
}
深搜
void DFS_MGraph(MGraph* graph, int v) { //v是起始顶点的索引visitMGraphNode(&graph->vex[v]);  //先访问MGraphVisited[v]=1;               //访问后做标记for (int i = 0; i < graph->nodeNum; ++i){ //访问v的所有邻接顶点
if( isEdge(graph->edge[v][i]) && MGraphVisited[i] == 0){ //若邻接且未访问DFS_MGraph(graph, i);  //再重复操作}}
}
广搜
void BFS_MGraph(MGraph* graph, int v) { //起始顶点下标vint que[MaxNodeNum];    //队列存储待访问的顶点下标int rear = 0, front = 0, cur;rear = (rear + 1) % MaxNodeNum; //形成循环数组防止溢出(后移一格)que[rear] = v;          //下标v入队MGraphVisited[v] = 1;   //标记下标为v的顶点(广度遍历标记的是入队的顶点)while (front != rear) { //队列不为空时front = (front + 1) % MaxNodeNum; //访问队头(front后移一格,这里此时front与rear相同)cur = que[front];   //cur现为队头,同时也为刚入队在队尾的顶点标号vvisitMGraphNode(&graph->vex[cur]); //访问v标号存储的顶点for (int i = 0; i < graph->nodeNum; ++i) { //访问v的所有邻接且未被标记的顶点if (isEdge(graph->edge[cur][i]) && !MGraphVisited[i]) {rear = (rear + 1) % MaxNodeNum; //找到后将尾指针后移que[rear] = i;                  //将该顶点入队并放在队尾MGraphVisited[i] = 1;           //入队后做标记}}}
}

功能调用

void testMatrixGraph(MGraph* grap) {  const char* nodeName[] = { "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8" };  initMGraph(grap, nodeName, sizeof(nodeName) / sizeof(nodeName[0]), 0, 0);  addMGraphEdge(grap, 0, 1, 1);  addMGraphEdge(grap, 0, 2, 1);  addMGraphEdge(grap, 1, 3, 1);  addMGraphEdge(grap, 1, 4, 1);  addMGraphEdge(grap, 2, 5, 1);  addMGraphEdge(grap, 2, 6, 1);  addMGraphEdge(grap, 3, 7, 1);  addMGraphEdge(grap, 4, 7, 1);  addMGraphEdge(grap, 5, 6, 1);  
}
int main() {MGraph g1;testMatrixGraph(&g1);printf("graph have %d edge!\n", g1.edgeNum);DFS_MGraph(&g1, 0);initVisited();printf("\n");BFS_MGraph(&g1, 0);return 0;
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Quarkus - 超音速亚原子Java,开启云原生应用新视界!

Quarkus - 超音速亚原子Java框架 Quarkus 是一个以云为中心、优先考虑&#xff08;Linux&#xff09;容器的框架&#xff0c;专为编写 Java 应用而设计。它旨在帮助开发者更轻松地构建和部署大规模的容器化 Java 应用&#xff0c;采用了一系列现代开发理念和标准。 核心特点 …

如何查看GPU运行情况:使用 Conda 安装 nvitop 新手指南

文章目录 🔍 1. 为什么推荐使用 Conda 环境安装 📥 2. 安装步骤 步骤 1: 安装 Miniconda 或 Anaconda (如果你还没有安装的话) 步骤 2: 创建并激活一个专门的 Conda 环境 步骤 3: 在 Conda 环境中安装 nvitop 步骤 4: 验证安装 ⚠️ 3. 疑难解答 📖 4. nvitop 的基本使用…

遥感机器学习专栏简介

专栏定位与受众本专栏聚焦「机器学习 遥感应用」的落地实践&#xff0c;专为遥感相关专业大学生、刚入门的遥感工程师、机器学习爱好者打造。避开纯理论堆砌&#xff0c;以「实验课式实操」为核心&#xff0c;帮你解决 “懂理论但不会用代码落地”“遥感数据处理与模型结合难”…

【更新至2024年】1996-2024年各省农业总产值数据(无缺失)

【更新至2024年】1996-2024年各省农业总产值数据&#xff08;无缺失&#xff09; 1、时间&#xff1a;1996-2024年 2、来源&#xff1a;国家统计局、各省年检 3、指标&#xff1a;农业总产值 4、范围&#xff1a;31省 5、缺失情况&#xff1a;无缺失 6、指标解释&#xf…

大语言模型预训练流程

大语言模型训练流程 Pre-training → SFT → RLHF阶段1&#xff1a;预训练Pre-training 海量无标注文本数据训练自监督学习机制学习语言基础知识掌握语法、语义、常识形成语言表示能力 核心目标&#xff1a;建立模型的语言理解和文本生成基础能力 阶段2&#xff1a;监督微调Sup…

Zookeeper:分布式协调服务

一、概念ZooKeeper 是一个分布式的、开源的分布式应用程序协调服务&#xff0c;为分布式应用提供一致性、配置管理、命名服务、分布式同步和组服务等。可以把它想象成一个为分布式系统提供的“文件系统”“通知机制”&#xff0c;但它存储的不是普通的文件&#xff0c;而是少量…

海盗王客户端BMP纹理图片解密

海盗王客户端的纹理贴图bmp文件有些是加密&#xff0c;很多人想解密并修改替换&#xff0c;现在给出解密的python代码&#xff1a; import os import struct import copy from pathlib import Pathclass TexEncode:def __init__(self):self.MAGIC_BYTES bmp.x # 魔法字节标识…

《链式二叉树常用操作全解析》

目录 一.求链式二叉树节点个数 二.求链式二叉树叶子节点个数 三.求链式二叉树第k层节点个数 四.求链式二叉树的深度/高度 五.链式二叉树查找值为x的节点 六.链式二叉树的销毁 七. 测试函数 八. 总结: 前言: 在学习链式二叉树的常用操作之前 我们需要手动创建一个二叉树 在…

YOLO11目标检测运行推理简约GUI界面

YOLO11推理简约GUI界面使用方法&#xff1a;支持pt和onnx格式模型,并且自动检测设备&#xff0c;选择推理设备选择推理图片所在的文件夹 选择推理后的结果保存地址选择所需要的置信度阈值点击开始推理&#xff0c;程序自动运行 并在下方实时显示推理进度非常方便不用每次都改代…

集值优化问题:理论、应用与前沿进展

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 1. &#x1f4da; 集值优化问题概述 集值优化问题主要研究目标函数为…

提示工程架构师分享:如何用提示词升级职业教育的实操案例教学?(万字长文来袭,高能预警!!!)

引言&#xff1a;实操案例教学的“困境”&#xff0c;终于有了破局思路&#xff1f; 晚上10点&#xff0c;汽修专业的王强老师还在电脑前修改《汽车发动机异响故障排查案例》——这已经是他本周第四次调整方案了&#xff1a; 第一次授课时&#xff0c;学生反馈“案例太理想化&a…

「日拱一码」087 机器学习——SPARROW

目录 SPARROW 介绍 核心思想&#xff1a;稀疏掩码训练 与 Lottery Ticket Hypothesis (LTH) 的关系 代码示例 代码关键点解释&#xff1a; 在机器学习领域&#xff0c;"SPARROW" 并不是一个像 Scikit-learn、TensorFlow 或 PyTorch 那样广为人知的通用框架或算法…

18、决策树与集成学习 - 从单一智慧到群体决策

学习目标:理解决策树的构建原理和分裂标准,掌握信息增益、基尼系数等概念,学会决策树的剪枝方法,深入理解集成学习的思想,掌握随机森林和梯度提升的基本原理。 > 从第17章到第18章:从概率模型到规则模型 在第17章中,我们学习了逻辑回归——一个基于概率的线性分类器…

王道计算机组成原理 学习笔记

第一章计算机系统概述1.1计算机的发展历程1.2计算机系统层次结构1.2.11.2.2 计算机硬件的基本组成1.2.2 各个硬件的工作原理1.2.3 计算机软件1.2.4 计算机系统的层次结1.2.5 计算机系统的工作原理1.3计算机的性能指标第二章数据的表示和运算第三章存储系统第四章指令系统第五章…

Oracle 笔记1 表空间及用户

Oracle 笔记1 表空间及用户1 安装Oracle2 创建表空间3 创建表空间用户1. 核心管理用户2. 示例与工具用户3. 系统与服务用户4. 创建表空间用户5. 修改表空间用户特性OracleMySQL开发商Oracle 公司最初由 MySQL AB 开发&#xff0c;后被 Sun 收购&#xff0c;现属 Oracle 公司数据…

MyBatis主键返回机制解析

关于 MyBatis 主键返回的深入解释 核心问题&#xff1a;信息隔离 数据库和应用程序是两个独立的系统&#xff1a; 数据库在服务器上执行 INSERT 操作并生成主键应用程序在另一个进程或甚至另一台机器上运行如果没有明确的机制&#xff0c;应用程序无法自动知道数据库生成了什么…

【Python】Python内置函数大全解析(附源码)

目录专栏导读前言&#x1f680; 功能特性1. 全面的函数覆盖2. 多种查询工具3. 完整的测试验证&#x1f6e0;️ 使用方法基本使用交互式查询运行测试&#x1f4da; 支持的内置函数分类数学运算 (13个)类型转换 (8个)序列操作 (8个)迭代器 (6个)输入输出 (3个)对象操作 (31个)&am…

每日算法题推送

题目1&#xff1a;快乐数 我们先来结合实例看一下判断快乐数的整个过程&#xff1a; 结合题目可以知道&#xff0c;如果一个数是快乐数&#xff0c;那么这个数最终就会变成1&#xff0c;如果一个数不是快乐数&#xff0c;那么变化序列最终就会陷入循环。想一下&#xff0c;如果…

Oracle体系结构-数据文件(Data Files)

一、 数据文件的本质与原理 物理存储的基石&#xff1a; 数据文件是 Oracle 数据库在操作系统层面最核心、最基础的物理存储单元。它们是存储在服务器硬盘&#xff08;或存储阵列&#xff09;上的操作系统文件&#xff08;如 .dbf, .ora 扩展名常见&#xff0c;但非强制&#x…

【C++练习】18.C++求两个整数的最小公倍数(LCM)

目录C求两个整数的最小公倍数(LCM)的方法方法一&#xff1a;利用最大公约数(GCD)计算代码实现方法二&#xff1a;逐次增加法代码实现方法三&#xff1a;质因数分解法代码实现方法比较处理大数和特殊情况改进版GCD方法实现 C求两个整数的最小公倍数(LCM)的方法 最小公倍数(LCM)是…