1.原图与邻接表存储图
顶点 | 邻接关系 |
---|---|
V1 | V2----V3 |
V2 | V1----V4----V5 |
V3 | V1----V6----V7 |
V4 | V2----V5----V8 |
V5 | V2----V4 |
V6 | V3 |
V7 | V3 |
V8 | V4 |
2.手算图的DFS搜索
第一次开始直接访问V1,V1的邻接顶点是V2、V3
第二次访问顶点V1的第一个邻接顶点V2,V2当前没有访问过,可以访问,访问V2,V2的邻接顶点是V1、V4、V5
第三次访问顶点V2的第一个邻接顶点V1,V1已经在第一次时候访问过了,不能访问,接着访问顶点V2第二个邻接点V4,V4当前没有访问过,可以访问,访问V4,V4的邻接顶点是V2、V5、V8
第四次访问顶点V4的第一个邻接顶点V2,V2已经在第二次的时候访问过了,不能访问,接着访问V4的第二个邻接点V5,V5当前没有访问过,可以访问,访问V5,V5的邻接顶点是V2、V4
第五次访问顶点V5的第一个邻接顶点V2,V2已经在第二次的时候访问过了,不能访问,接着访问V5的第二个邻接点V4,V4已经在第三次访问过了,也不能访问,最后V5没有其他邻接点,接着回退到第四次,当前的顶点是V4,当前访问到的邻接点是V5,接着访问V4的下一个邻接点是V8,V8没有访问过,可以访问,访问V8,V8的邻接顶点是V4
第六次访问顶点V8的第一个邻接顶点V4,V4已经在第三次访问过了,不能访问,此时的V8所有邻接顶点访问完成,回退到第四次,当前的顶点是V4,当前访问到的邻接顶点是V8,接着发现V4所有邻接顶点访问完成,继续回退到第三次,当前顶点是V2,当前访问的邻接点是V4,接着访问V2的第三个邻接顶点V5,发现V5在第四次的时候访问过了,继续回退到第二次,当前顶点是V1,当前所访问到的邻接顶点是V2,接着访问V1的第二个邻接顶点V3,发现没有访问,访问V3,顶点V3的邻接顶点是V1、V6、V7
第七次访问顶点V3的第一个邻接顶点V1,发现V1在第一次的时候访问过来,不能访问,接着访问V3的第二个邻接顶点V6,没有访问,访问V6,顶点V6的邻接顶点是V3、V7
第八次访问顶点V6的第一个邻接顶点V3,发现V3在第六次的时候访问过了,不能访问,接着访问顶点V6的第二个邻接顶点V7,没有访问,访问V7,顶点V7的邻接顶点是V3、V6
第九次访问顶点V7的第一个邻接顶点是V3,发现V3在第六次已经访问过了不能访问,接着访问顶点V7第二个邻接顶点V6,发现V6在第七次的时候访问过了,所以回退到第八次,当前顶点是V6,当前所访问的邻接顶点是V7,发现V7是顶点V6的最后一个邻接顶点,所以继续回退到第七次,当前顶点是V3,当前所访问的邻接顶点是V6,接着访问顶点V3的下一个顶点,访问顶点V3的第三个顶点V7,发现V7已经访问过了且V7是顶点V3的最后一个邻接顶点,所以继续回退到第6次,当前的顶点是V1,当前所访问的邻接顶点是V3,且发现邻接点V3是顶点V1的最后一个邻接点,所以继续回退,最后V3是访问的最后一个顶点,退出程序.
所以以顶点V1开始DFS搜索,访问的顺序为:V1 V2 V4 V5 V8 V3 V6 V7
3.伪代码:
1.访问顶点V,同时visited[V]设置访问过的标志1
2.循环遍历每一个顶点的所有邻接点 {
//如果当前顶点没有访问过,并且该邻接点是该顶点的邻接点
//那么就dfs搜索吧该邻接点重新作为顶点去搜索,下一次查找该顶点的邻接点
}
4.dfs图搜索总结
对于dfs搜索肯定是在循环中进行调用递归的算法,每一次去搜索顶点的邻接点,如果找到了该顶点的邻接点,那么dfs到达下一层,此时的顶点是作为上一次的邻接点,继续这样循环操作,就是一直寻找顶点的邻接点,调用递归,邻接点变成顶点,又继续搜索此时的顶点的邻接点,一直搜索每一个顶点的邻接点,当出现了这种情况下就停止搜索,此时的循环就起到了很好的作用,当dfs搜索到某一层的时候,此时没有找到该顶点的邻接点,那么返回上一层,搜索该顶点的下一个邻接点,如图所示。
有三个顶点,ABC,其中A存储邻接点B和C,如果这个图按照DFS搜索。
1.先访问A点,设置A已经访问过的标志
2.在循环中进行遍历每一个顶点的邻接点,此时发现A的第一个邻接点是B,然后递归调用下一层,访问B,设置B访问过的标志,接着发现B没有邻接点,此时该层结束,返回到上一层去,由于是在循环中进行的,此时的递归结束后,循环查找A的下一个邻接点,那么就是C。
这就是循环的好处,每一次DFS结束后,会跳到上一次从哪一个邻接点调用的地方去,循环到该顶点的下一个邻接点。
5.邻接矩阵与DFS算法
#include <stdio.h>
typedef char VertextType;
#define MAX_VERTEXT 10
#pragma warning(disable:4996)
//定义一个图
typedef struct Graph {
VertextType adj[MAX_VERTEXT]; //顶点
int arc[MAX_VERTEXT][MAX_VERTEXT]; //邻接矩阵
int vexnum, arcnum; //顶点数 弧数
}MGraph;
//确定顶点位置
int LocateVertext(MGraph* G, VertextType v) {
int i = 0;
while (i < G->vexnum && v != G->adj[i]) i++;
if (G->adj[i] == v) return i;
else return -1;
}
//用邻接矩阵创建图
void CreateDN(MGraph* G) {
int i, j, k, weight;
VertextType v1, v2;
printf("输入顶点数和弧数:");
scanf("%d %d", &G->vexnum, &G->arcnum);
getchar();
printf("输入%d个顶点:", G->vexnum);
for (i = 0; i < G->vexnum; i++) {
scanf("%c", &G->adj[i]);
getchar();
}
//初始化邻接矩阵
for (i = 0; i < G->vexnum; i++) {
for (j = 0; j < G->vexnum; j++) {
G->arc[i][j] = 0;
}
}
for (k = 0; k < G->arcnum; k++) {
printf("输入第%d组顶点和权值:", k + 1);
scanf("%c %c %d", &v1, &v2, &weight);
getchar();
i = LocateVertext(G, v1);
j = LocateVertext(G, v2);
if (i != -1 && j != -1) {
G->arc[i][j] = weight;
G->arc[j][i] = weight;
}
}
}
//显示邻接矩阵
void display_Graph(MGraph* G) {
int i, j;
printf(" ");
for (i = 0; i < G->vexnum; i++) {
printf("%3c", G->adj[i]);
}
printf("\n");
for (i = 0; i < G->vexnum; i++) {
printf("%3c", G->adj[i]);
for (j = 0; j < G->vexnum; j++) {
printf("%3d", G->arc[i][j]);
}
printf("\n");
}
}
//显示各个顶点与邻接点关系
void display_vex(MGraph* G) {
int i, j;
for (i = 0; i < G->vexnum; i++) {
printf("%3c的邻接点:", G->adj[i]);
for (j = 0; j < G->vexnum; j++) {
if (G->arc[i][j] != 0) {
printf("%3c", G->adj[j]);
}
}
printf("\n");
}
}
//设置访问数组
int visited[MAX_VERTEXT];
void DFS(MGraph G, int v) {
printf("%c ", G.adj[v]);
visited[v] = 1; //设置访问标志
for (int i = 0; i < G.vexnum; i++) {
//如果当前顶点没有访问过,并且该邻接点是该顶点的邻接点
if (!visited[i] && G.arc[v][i] != 0) DFS(G, i);
}
}
int main() {
MGraph G;
int i, j;
CreateDN(&G); //创建邻接矩阵
printf("\n邻接矩阵表示\n");
display_Graph(&G); //显示邻接矩阵
printf("\n显示各个顶点与邻接点关系\n");
display_vex(&G);
printf("DFS搜索图的顶点:");
DFS(G, 0);
return 0;
}
/*
邻接矩阵运行接过
输入顶点数和弧数:5 6
输入5个顶点:A B C D E
输入第1组顶点和权值:A B 2
输入第2组顶点和权值:A C 4
输入第3组顶点和权值:A E 9
输入第4组顶点和权值:B E 3
输入第5组顶点和权值:C D 6
输入第6组顶点和权值:D E 5
邻接矩阵表示
A B C D E
A 0 2 4 0 9
B 2 0 0 0 3
C 4 0 0 6 0
D 0 0 6 0 5
E 9 3 0 5 0
显示各个顶点与邻接点关系
A的邻接点: B C E
B的邻接点: A E
C的邻接点: A D
D的邻接点: C E
E的邻接点: A B D
DFS搜索图的顶点:A B E D C
*/
6.邻接表与DFS
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
#define MAX_VERTEXT 10
typedef char VertexType;
typedef struct ArcNode {
VertexType vex; //顶点
int adjvex; //邻接点序号
struct ArcNode* next; //指向下一个邻接点的指针域
}ArcNode;
typedef struct VertexNode { //定义表头
VertexType data;
struct ArcNode* next;
}VertexNode;
typedef struct {
VertexNode vertex[MAX_VERTEXT]; //顶点
int arcnum, vexnum; //弧数 顶点
}MGraph;
//查找
int loadcateVertex(MGraph* G, VertexType v) {
int i = 0;
while (i < G->vexnum && G->vertex[i].data != v) i++;
if (G->vertex[i].data == v) return i;
else return -1;
}
//创建邻接表
void Create(MGraph* G) {
ArcNode* s;
VertexType v1, v2;
int weight;
int i, j;
int k1, k2;
printf("输入顶点数和弧数:");
scanf("%d %d", &G->vexnum, &G->arcnum);
getchar();
printf("输入%d个顶点:", G->vexnum);
for (i = 0; i < G->vexnum; i++) {
scanf("%c", &G->vertex[i].data);
getchar();
G->vertex[i].next = NULL;
}
for (i = 0; i < G->arcnum; i++) {
printf("输入第一个顶点和邻接点和权值:");
scanf("%c %c %d", &v1, &v2, &weight);
getchar();
k1 = loadcateVertex(G, v1);
k2 = loadcateVertex(G, v2);
s = (ArcNode*)malloc(sizeof(ArcNode));
s->vex = v2; //初始化顶点
s->adjvex = k2; //初始化序号
//头插法连接到顶点表中
s->next = G->vertex[k1].next;
G->vertex[k1].next = s;
s = (ArcNode*)malloc(sizeof(ArcNode));
s->vex = v1; //初始化顶点
s->adjvex = k1; //初始化序号
//头插法连接到顶点表中
s->next = G->vertex[k2].next;
G->vertex[k2].next = s;
}
}
//访问各个顶点的邻接表
void display_vertex(MGraph* G) {
ArcNode* s = NULL;
int i;
for (i = 0; i < G->vexnum; i++) {
s = G->vertex[i].next;
printf(" %c的邻接点:", G->vertex[i].data);
while (s != NULL) {
printf("%c ", s->vex);
s = s->next;
}
printf("\n");
}
}
int visided[MAX_VERTEXT]; //设置访问标志
void DFS(MGraph* G, int v) {
ArcNode* s = NULL;
if (!visided[v]) printf("%c ", G->vertex[v].data);
visided[v] = 1;
s = G->vertex[v].next;
while (s != NULL) {
//判断当前邻接点是否访问
if (!visided[s->adjvex]) DFS(G, s->adjvex);
s = s->next;
}
}
int main() {
MGraph G;
Create(&G); //创建邻接表
display_vertex(&G); //显示各个顶点邻接信息
printf("DFS搜索结果:");
DFS(&G, 0);
return 0;
}
/*
输入顶点数和弧数:5 6
输入5个顶点:A B C D E
输入第一个顶点和邻接点和权值:A B 2
输入第一个顶点和邻接点和权值:A C 4
输入第一个顶点和邻接点和权值:A E 9
输入第一个顶点和邻接点和权值:B E 3
输入第一个顶点和邻接点和权值:C D 6
输入第一个顶点和邻接点和权值:D E 5
A的邻接点:E C B
B的邻接点:E A
C的邻接点:D A
D的邻接点:E C
E的邻接点:D B A
DFS搜索结果:A E D C B
*/
由于邻接表采用头插法结构的链表,所以利用DFS搜索的结果与邻接矩阵的DFS搜索的结果不一样
邻接矩阵DFS:A B E D C
邻接表DFS:A E D C B