图的遍历(深度优先遍历,DFS)

article/2025/10/28 19:05:43

1.概念

图的遍历操作是从图中某一顶点出发,对图中所有顶点访问一次且仅访问一次

(1)在图中,遍历的起始顶点是编号最小的顶点

(2)某个起点到达不了所有顶点,则多次调用访问所有顶点

(3)为避免遍历因回路而陷入死循环,附设置访问标志数组visited[n](其中是对应所有的顶点下标,访问过设置为1;未访问过设置为0)

(4)所有结点的编号均从0开始

2.思路

(1)访问顶点v;

(2)从v的未被访问的邻接点中选取一个顶点w(选取规则是找相邻编号最小的结点),从w出发进行深度优先遍历;

(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

例如下图:(图片来自懒猫老师《数据结构》相关课程讲义)

伪代码:

寻找下一个访问点的方法:

(1)邻接矩阵:因为邻接矩阵的列的编号顺序是从小到大,所以寻找下一个访问点可以直接访问当前访问点对应行的第一个非零元素(w未被访问)

(2)邻接表:访问该点对应的边表,且前提是边表的所有结点是由下标从小到大进行排列

3.代码实现

3.1功能函数

(1)邻接矩阵的深度优先遍历

void DFSTraverse(int arc[][MAX_VERTEX], DataType *vertex, int *visited, int vertexNum,int v) { //v是遍历的起始位置的编号static int flag = 0;if (flag == 0) {//第一次需要初始化initvertex(vertexNum, visited);flag = 1;}visit(vertex, v); //输出访问过的顶点信息visited[v] = 1;for (int i = 0; i < vertexNum; i++) { //因为是邻接矩阵,所以编号的顺序本来就是由小到大的.所以不用遍历找if (arc[v][i] != 0 && visited[i] == 0)DFSTraverse(arc, vertex, visited, vertexNum, i); //二维数组传参,调用时实参直接写数组名}
}

(2)邻接表的深度优先遍历

void DFSTraverse(VertexNode *adjList, int *visited, int vertexNum, int v) {static int flag = 0;if (flag == 0) {//第一次需要初始化initvertex(vertexNum, visited);flag = 1;}visit(adjList, v); //输出访问过的顶点信息visited[v] = 1;ArcNode *p = adjList[v].firstEdge;while (p != NULL) {if (visited[p->adjvex] == 0)DFSTraverse(adjList, visited, vertexNum, p->adjvex);p = p->next;}
}
void initvertex(int vertexNum, int *visited) { //初始化visited函数for (int i = 0; i < vertexNum; i++)visited[i] = 0;
}void visit(VertexNode *adjList, int v) { //输出访问过的顶点信息printf("%d ", adjList[v].vertex);//记得改变输出时要改变数据类型
}void ranklist(VertexNode *adjList, int vertexNum) { //将边表进行升序的排序,便于遍历操作ArcNode *p, *q;int temp;for (int i = 0; i < vertexNum; i++) {p = adjList[i].firstEdge;q = p;while (p != NULL) {while (q != NULL) {if (p->adjvex > q->adjvex) {temp = p->adjvex;p->adjvex = q->adjvex;q->adjvex = temp;}q = q->next;}p = p->next;}}
}

3.2完整代码及测试

(1)邻接矩阵

1)图_邻接矩阵.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_VERTEX 10//最大的顶点个数
typedef int DataType;//以下是无向图的定义
void MGraph(DataType *vertex, int arc[][MAX_VERTEX], int vertexNum, int arcNum) { //初始化构造图(邻接矩阵法)printf("请逐个输入顶点的内容:");DataType x;DataType vi, vj; //构建邻接矩阵时,一条边的两个结点编号for (int i = 0; i < vertexNum; i++) { //顶点数组赋值scanf("%d", &x);vertex[i] = x;}for (int i = 0; i < vertexNum; i++) //初始化邻接矩阵for (int j = 0; j < vertexNum; j++)arc[i][j] = 0;int count = 1;for (int i = 0; i < arcNum; i++) { //依次输入每一条边printf("请输入第%d条边依附的两个顶点的编号:", count++);scanf("%d %d", &vi, &vj); //输入该边依附的顶点的编号arc[vi][vj] = 1; //置有边标志arc[vj][vi] = 1;}}void printMGraph(DataType *vertex, int arc[][MAX_VERTEX], int vertexNum) { //输出printf("vertex:");for (int i = 0; i < vertexNum; i++) {printf("%d ", vertex[i]);}printf("\n");printf("arc:\n");for (int i = 0; i < vertexNum; i++) {for (int j = 0; j < vertexNum; j++) {if (j == vertexNum - 1)printf("%d\n", arc[i][j]);elseprintf("%d ", arc[i][j]);}}}int isLinked(int arc[][MAX_VERTEX], int i, int j) { //两顶点i,j是否有边相连,1是相连,0是不相连if (arc[i][j] == 1)return 1;elsereturn 0;
}int nodeDepth(int arc[][MAX_VERTEX], int index, int vertexNum) { //任意一顶点的度//无向图任意遍历行\列求和int count = 0;for (int i = 0; i < vertexNum; i++) {if (arc[index][i] == 1)count++;}return count;
}void initvertex(int vertexNum, int *visited) { //初始化visited函数for (int i = 0; i < vertexNum; i++)visited[i] = 0;
}void visit(DataType *vertex, int v) { //输出访问过的顶点信息printf("%d ", vertex[v]);}void DFSTraverse(int arc[][MAX_VERTEX], DataType *vertex, int *visited, int vertexNum,int v) { //v是遍历的起始位置的编号static int flag = 0;if (flag == 0) {//第一次需要初始化initvertex(vertexNum, visited);flag = 1;}visit(vertex, v); //输出访问过的顶点信息visited[v] = 1;for (int i = 0; i < vertexNum; i++) { //因为是邻接矩阵,所以编号的顺序本来就是由小到大的.所以不用遍历找if (arc[v][i] != 0 && visited[i] == 0)DFSTraverse(arc, vertex, visited, vertexNum, i); //二维数组传参,调用时实参直接写数组名}
}

2)图的测试_邻接矩阵.c

#include "图_邻接矩阵.h"main() {DataType vertex[MAX_VERTEX];//储存所有的顶点int arc[MAX_VERTEX][MAX_VERTEX];//邻接矩阵,结点间的连通关系int vertexNum, arcNum; //结点个数,边的个数printf("输入顶点个数:");scanf("%d", &vertexNum);printf("输入边个数:");scanf("%d", &arcNum);MGraph(vertex, arc, vertexNum, arcNum);printMGraph(vertex, arc, vertexNum);printf("测试判断两顶点是否相连,请输入两个顶点下标:");int i, j;scanf("%d %d", &i, &j);if (isLinked(arc, i, j) == 1)printf("相连!\n");elseprintf("不相连!\n");printf("测试求顶点的度,请输入一个顶点下标:");int index;scanf("%d", &index);printf("该顶点的度为:%d\n", nodeDepth(arc, index, vertexNum));printf("测试邻接矩阵的深度优先遍历:\n");int visited[vertexNum];//判断结点是否访问过,访问过设置1,未访问过为0int v;printf("请输入深度优先遍历的第一个结点编号:");scanf("%d", &v);printf("深度优先遍历序列:");DFSTraverse(arc, vertex, visited, vertexNum, v);}

3)测试输出

测试用例:(无向图)

输出:(注意区分结点的内容和编号,结点数据从1开始,结点编号从0开始)

(2)邻接表

1)图_邻接表.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_VERTEX 10//最大的顶点个数
typedef char DataType;/*
当DataType为char时要特别注意输入时空格和换行符,分别利用getchar()
和fflush(stdin);来清空内存区
*/
typedef struct ArcNode { /*边表结点*/int adjvex;//边表数据域,即下标struct ArcNode *next; //指针域
} ArcNode;typedef struct VertexNode { /*顶点表结点*/DataType vertex;//顶点的数据ArcNode *firstEdge; //指向储存该顶点所连接所有结点的边表
} VertexNode;
void initVertex(DataType *, int);//以下是有向图的定义
void ALGraph(DataType *vertex, VertexNode *adjList, int vertexNum, int arcNum) { //初始化构造图(邻接表法)int vi, vj;int count = 0;initVertex(vertex, vertexNum);for (int i = 0; i < vertexNum; i++) { //初始化顶点表adjList[i].vertex = vertex[i];adjList[i].firstEdge = NULL;}for (int i = 0; i < arcNum; i++) {//输入边的信息储存在边表中printf("请输入第%d条边依附的两个顶点的编号(方向->):", count++);fflush(stdin);//清除输入缓冲区(否则这里就会直接跳过scanf)
/*当DataType为int时要去掉上面这个语句*/scanf("%d %d", &vi, &vj); //输入该边依附的顶点的编号ArcNode *s;s = (ArcNode *)malloc(sizeof(ArcNode));if (s != NULL) {s->adjvex = vj;s->next = adjList[vi].firstEdge; //头插法建立链表adjList[vi].firstEdge = s;} elseprintf("init error!\n");}
}void initVertex(DataType *vertex, int vertexNum) {//输入函数printf("请逐个输入顶点的内容:");DataType x;for (int i = 0; i < vertexNum; i++) { //顶点数组赋值getchar();//吸收空格,当DataType为int时要去掉这个语句scanf("%c", &x);vertex[i] = x;}
}void printALGraph(VertexNode *adjList, int vertexNum) {printf("vertex  firstEdge\n");ArcNode *p ;for (int i = 0; i < vertexNum; i++) {printf("%3c -->", adjList[i].vertex);p = adjList[i].firstEdge;while (p != NULL) {printf("%d -->", p->adjvex);p = p->next;}printf("NULL\n");printf("\n");}
}int isLinked(VertexNode *adjList, int i, int j) { //两顶点i,j是否有边相连,1是相连,0是不相连ArcNode *p = adjList[i].firstEdge ;while (p != NULL) {if (p->adjvex == j)return 1;elsep = p->next;}p = adjList[j].firstEdge;while (p != NULL) {if (p->adjvex == i)return 1;elsep = p->next;}return 0;
}int nodeDepth(VertexNode *adjList, int index, int vertexNum) { //任意一顶点的度int count = 0;ArcNode *p = adjList[index].firstEdge;while (p != NULL) {count++;p = p->next;}return count;
}void freeArcNode(VertexNode *adjList, int vertexNum) {ArcNode *p;ArcNode *temp;for (int i = 0; i < vertexNum; i++) {p = adjList[i].firstEdge ;while (p != NULL) {temp = p;p = p->next;free(temp);}}
}void initvertex(int vertexNum, int *visited) { //初始化visited函数for (int i = 0; i < vertexNum; i++)visited[i] = 0;
}void visit(VertexNode *adjList, int v) { //输出访问过的顶点信息printf("%c ", adjList[v].vertex);//记得改变输出时要改变数据类型
}void DFSTraverse(VertexNode *adjList, int *visited, int vertexNum, int v) {static int flag = 0;if (flag == 0) {//第一次需要初始化initvertex(vertexNum, visited);flag = 1;}visit(adjList, v); //输出访问过的顶点信息visited[v] = 1;ArcNode *p = adjList[v].firstEdge;while (p != NULL) {if (visited[p->adjvex] == 0)DFSTraverse(adjList, visited, vertexNum, p->adjvex);p = p->next;}
}void ranklist(VertexNode *adjList, int vertexNum) { //将边表进行升序的排序,便于遍历操作ArcNode *p, *q;int temp;for (int i = 0; i < vertexNum; i++) {p = adjList[i].firstEdge;q = p;while (p != NULL) {while (q != NULL) {if (p->adjvex > q->adjvex) {temp = p->adjvex;p->adjvex = q->adjvex;q->adjvex = temp;}q = q->next;}p = p->next;}}
}

2)图的测试_邻接表.c

#include "图_邻接表.h"int main() {DataType vertex[MAX_VERTEX];//储存所有的顶点int vertexNum, arcNum; //结点个数,边的个数printf("输入顶点个数:");scanf("%d", &vertexNum);printf("输入边个数:");scanf("%d", &arcNum);VertexNode adjList[vertexNum];//顶点表ALGraph(vertex, adjList, vertexNum, arcNum);ranklist(adjList, vertexNum);printALGraph(adjList, vertexNum);printf("测试判断两顶点是否相连,请输入两个顶点下标:");int i, j;scanf("%d %d", &i, &j);if (isLinked(adjList, i, j) == 1)printf("相连!\n");elseprintf("不相连!\n");printf("测试求顶点的度,请输入一个顶点下标:");int index;scanf("%d", &index);printf("该顶点的度为:%d\n", nodeDepth(adjList, index, vertexNum));printf("测试邻接表的深度优先遍历:\n");int visited[vertexNum];//判断结点是否访问过,访问过设置1,未访问过为0int v;printf("请输入深度优先遍历的第一个结点编号:");scanf("%d", &v);printf("深度优先遍历序列:");DFSTraverse(adjList, visited, vertexNum, v);freeArcNode(adjList, vertexNum);
}

3)测试输出

测试用例:(有向图)

输出: (结点数据为char类型时要注意输入时的空格和换行符的读取问题)

初学小白,有错误欢迎指正喔!


http://chatgpt.dhexx.cn/article/ZpBxf2jp.shtml

相关文章

数据结构 第六章 图——图的遍历

6.5 图的遍历 在前面我们知道&#xff0c;树是一种非线性结构&#xff0c;为了方便它在计算机中的存储&#xff0c;对树进行遍历使它线性化。 而图同样也是一种非线性结构&#xff0c;但是图又是一种不同于树的多对多结构&#xff0c;所以在前面我们将其转换为了多个一对多的结…

数据结构——图(图的遍历)

图的遍历 图的遍历深度优先遍历&#xff08;DFS&#xff09;DFS算法效率分析深度优先遍历算法的实现广度优先搜索遍历&#xff08;BFS&#xff09;BFS算法效率分析DFS与BFS算法比较 图的遍历 遍历定义&#xff1a;从已给的连通图中某一顶点出发&#xff0c;沿着一些边访遍图中所…

图的遍历 (深度优先遍历和广度优先遍历)

一. 什么是深度优先遍历 深度优先遍历可定义如下&#xff1a;首先访问出发点v&#xff0c;并将其标记为已访问过&#xff1b;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过&#xff0c;则以w为新的出发点继续进行深度优先遍历&#xff0c;直至图中所有和源点v有路径相通的…

图的遍历

图的遍历 介绍 是从图的某一顶点出发&#xff0c;按照某种搜索方式对图中所有顶点访问一次且仅一次。图的遍历可以解决很多搜索问题&#xff0c;在实际中应用非常广泛。图的遍历根据搜索方式的不同&#xff0c;分为广度优先搜索和深度优先搜索。 一.深度优先遍历 1.1介绍 深…

视频和图片合成软件,简单快速合成视频和图片

怎么把小视频和图片合成起来&#xff1f;有简单好上手的教程吗&#xff1f;今天就教大家简单几步&#xff0c;把视频和图片合成为照片视频。先看看用数码大师合成视频和图片的效果截图&#xff1a; 第一步&#xff1a;把图片一次性导入&#xff0c;为照片配上文字 点击“添加…

多张图片怎么合成gif?

多张图片怎么合成gif&#xff1f;gif动图是我们比较熟悉的一种网络聊天表情包&#xff0c;通常都是由图片或者视频转换而来的。很多小伙伴会选择用PS来制作GIF动图&#xff0c;但并不是所有小伙伴都会使用PS&#xff0c;所以一个自动简单&#xff0c;可以将图片或者视频直接转换…

android将图片做成视频播放,如何把图片做成视频【图文教程】

教你怎么将手机拍摄的一张张图片整合转换成视频播放更唯美。下面以直走婚纱mv电子相册为例。 安装好软件&#xff0c;先运行绿化程序&#xff0c;然后再运行软件&#xff0c;详情请参看使用说明txt文档。打开之后&#xff0c;有两个模式供你选择&#xff0c;左边是标准模式、右…

php把图片合成视频,如何把照片做成视频 照片音乐视频制作 并插入几段短视频片段...

如何把照片制作成视频&#xff1f;相信大家都已经有所耳闻了&#xff0c;把平时手机或者相机上拍摄的照片&#xff0c;还有拍摄的视频都可以合起来&#xff0c;再添加背景音乐就成了一个非常有纪念价值的视频了。然而已经不是只有照片和音乐的视频了&#xff0c;整个视频全是照…

视频转图片-人脸识别-合成视频

视频转图片-人脸识别-合成视频 代码&#xff1a; import cv2 import os,sys import numpy as npface_xml cv2.CascadeClassifier(r"C:\Users\lenovo\Desktop\python\jiqixuexi\haarcascade_frontalface_default.xml") eye_xml cv2.CascadeClassifier(r"C:\U…

怎样用计算机合并视频,电脑视频合并软件 , 怎样把多个视频合成为一个

昨天小编在搜梁博的歌曲《表态》的视频时(这首歌小编觉得真的很好听推荐下)在一个剪辑视频发现他将梁博在某综艺唱的歌曲全都剪辑在视频里。这里就运用到了一个剪辑视频知识&#xff0c;合并视频。既然看到小编就准备跟大家伙讲讲这个视频剪辑内容。如何把多个视频合并在一个视…

php合成视频特效,视频合并加转场效果

热爱视频后期剪辑的朋友都会知道&#xff0c;在视频的后期制作过程中&#xff0c;常见操作中就有视频合并这一项&#xff0c;及在视频之间加入转场效果&#xff0c;为影视编辑作品带来绚丽多彩的视觉效果&#xff0c;不禁会使人眼前一亮。接下来给大家介绍一款简易好用的视频编…

php 图片生成视频,图片转化为视频的方法 如何将照片制作成为视频

点击上方的下载地址&#xff0c;然后将软件进行安装。安装完毕后&#xff0c;打开软件在这个界面可以选择软件的比例大小和操作模式&#xff0c;我们选择“4:3”和“全功能模式”。 接着我们将要进行操作的图片导入到软件&#xff0c;点击“导入”后在“打开”界面选中所有的图…

ffmpeg使用(多个帧合成视频)

帧生成视频命令&#xff1a; ffmpeg -threads 2 -y -r 24 -i %05d.jpg output.mp4 视频生成帧命令&#xff08;按帧生成图片&#xff09;&#xff1a; ffmpeg -i checkpoints_dstt_car-turn_result.mp4 chaifen/%06d.png 1、下载ffmpeg安装包 https://github.com/BtbN/FFmpe…

matlab jpg合成gif,用MATLAB将照片合成视频或者GIF图片、以及Photoshop制作GIF图片

用MATLAB将照片合成视频或者GIF图片、以及Photoshop制作GIF图片 一、用MATLAB将照片合成视频(我使用的MATLAB是2015版本的) (1)、你需要需要合成视频的图片。 所有照片放在一个文件夹里面因为是使用Matlab的dir函数读取照片,所以读取时,你要先设置好文件名:图片名称按照“00…

FFmpeg初探——基于FFmpeg的图片合成视频

前言 商家在发布商品的时候&#xff0c;大部分情况下是没有视频的&#xff0c;这样往往会造成商品展示不全等问题&#xff0c;而视频制作又比较麻烦&#xff0c;为了解决此痛点&#xff0c;我们需要提供一键合成视频的功能。 之所以选择 FFmpeg&#xff0c;是因为我们期望后续能…

视频照片合成软件哪个好?快速把手机照片做成视频,简单操作,效果精美!

视频照片合成软件哪个好&#xff1f;怎么把照片合成视频&#xff1f;如何快速把手机照片做成视频&#xff1f; 这是我用数码大师把手机照片合成视频的效果截图&#xff1a; 第一步&#xff1a;快速导入多张照片&#xff0c;为照片配上文字 点击“添加相片”就能快速导入照片…

ffmpeg图片+音频合成视频

命令如下&#xff0c;个人纪录 ffmpeg -framerate 0.05 -f image2 -loop 1 -y -i d:/img/img%d.jpg -i d:/img/gyz.mp3 -s 1080*1920 -r 25 -t 100 d:/img/output.mp4 -framerate 速率&#xff0c;越小每张图片停留时间越长 -loop 循环一遍文件夹内的图片 -i 图片路径&#x…

用php把图片合成视频,图片音乐合成视频 多张图片合成视频|图片合成视频软件...

在网络上我们经常见到的电子相册其本质就是图片音乐合成视频&#xff0c;使用一些图片合成视频软件将多张图片合成视频&#xff0c;外加点炫酷的转场特效&#xff0c;so easy的就能完成了。o(*≧▽≦)ツ 想不想知道具体的操作过程&#xff1f;有兴趣的童鞋可以看看下文的~ 这是…

电脑图片合成视频用什么软件?3分钟快速教程,多张图片做成精美视频!

电脑图片合成视频怎么做&#xff1f;图片视频制作用什么软件好&#xff1f;现在大家的照片或图片很多&#xff0c;其实在电脑上把图片做成视频是非常方便的&#xff0c;还能整理好照片&#xff0c;节省空间&#xff0c;图片/照片视频看起来也更加美观。今天直接用数码大师教大家…

当请求类型是octet-stream时,SpringBoot 如何完成文件上传

一、问题背景 这个问题困扰了我一上午&#xff0c;搜索了很多博客&#xff0c;发现网上的springboot都是使用Multipart来接收文件&#xff0c;而客户端使用的是binary&#xff0c;用二进制流来上传文件的&#xff0c;下面记录一下我的解决历程。 二、基础知识 一个请求的参数…