图的深度优先搜索

1. 图的深度优先搜索是我们在学习对于图的遍历的一种很重要的方式,与树的深度优先搜索不同的是,图是有可能存在环路的,所以我们不能够直接像深度优先搜索树那样直接搜索,因为有环的时候会陷入一直递归下去的情况,所以需要增加一个标记符号,表示当前的顶点和边是已经被访问过的,下一次再遍历到这个已经被访问过的顶点或者是边的时候应该跳过,其余跟树的深度优先搜索是都是差不多的

2. 下面是具体的过程

① 使用什么存储方式来存储图?

对于图的存储我们主要有邻接矩阵、邻接表和边集三种存储方式

邻接矩阵:表示顶点之间的相邻关系的矩阵,邻接矩阵是图的顺序存储结构

邻接矩阵的实质上就是使用二维数组来表示图中顶点之间的关系

1)对于C语言我们可以使用结构体来进行模拟其中的过程,可以声明表示顶点的结构体和图的结构体,顶点的结构体中存放当前顶点的序号与一些其他信息,图的结构体里面可以声明一个顶点的结构体数组来表示图中的顶点的情况,另外可以声明一个边的二维数组来表示顶点中边的情况就OK了

2)对于Java语言来说直接使用二维数组来存储顶点之间的关系即可,而且使用二维数组在进行深度优先搜索的时候很方便,直接可以利用下标可以知道当前顶点的序号是什么

 

邻接表:是图的一种链式存储结构,所谓的邻接表就是对图中的每个顶点i创建一个单链表,每个单链表的第一个节点存放有关节点的信息,把这一节点看作是链表的表头,其余节点存放有关边的信息,因此邻接表由表单链表的表头形成的顶点表和单链表其余顶点形成的边表两部分组成,一般来说顶点表存放的是顶点信息和指向第一个边节点的指针,边表节点存放与当前节点相邻接顶点的序号和指向下一条边节点的指针

 

实际上邻接表的核心是需要为每一个节点都创建一个单链表,链表中存放的是当前节点的邻居,关键是如何利用我们的语言特性来表示相应的单链表的结构

1)所以我们在具体实现邻接表的时候可以灵活来进行实现,像C语言的话我们可以使用结构体数组来进行模拟,数组的下标表示节点的编号,而每个结构体数组中的成员可以存放一个结构体指针用来指向当前节点的所连接的边

2)像Java语言我们可以使用一个类,里面声明几个成员变量,比如当前节点的值,声明一个List集合用来存放当前节点的邻居节点,这样就完成了List集合来模仿单链表的过程,所以我们不一定是一定要单链表来进行实现,任何能够将当前节点与它的邻居连起来的数据结构都是可以的

 

② 下面采用的是邻接矩阵来存储图(比较方便)

对于图的标记主要有两种:一种是标记的是顶点已经被访问了,另外一种方式是标记边已经被访问过了,标记边可以声明一个表示当前节点的一维数组即可,标记边的话我们可以使用一个二维数组来进行标记假如对于无向图来说我们当前的边为被访问是当前标记数组中对应顶点的二维数组中的数值是大于0的,需要注意的是访问一条边我们需要将对应的位置进行减二,对于有向图来说也是类似的,而且更加简单只需要判断当前的二维数组中顶点对应的位置是否有边即可,访问过之后对应位置减去1即可

我们的目的是深度优先遍历图输出图中访问节点的先后顺序即可,所以我们标记顶点已经被访问过即可

③ 对于图的深度优先搜索我们的套路是在dfs的方法中传入一个表示当前顶点序号的参数,在dfs方法内部使用一个for循环来检查当前顶点连接的其他邻居

在递归方法中每访问一个节点那么我们就可以使用输出语句来进行输出,输出结果为深度优先搜索访问节点的顺序

3. 下面是具体的代码:

import java.util.Scanner;
/*
0--1->5
0--2->1
0--3->2
1--2->3
2--3->6
1--4->4
2--4->2
3--4->3
顶点个数: 5
边数: 8
 * */
//这里规定权重不为零
public class Main {
	static int visit[];
	static int graph[][];
	static int n;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("输入图中顶点的个数: ");
		n = sc.nextInt();
		visit = new int[n];
		graph = new int[n][n];
		System.out.println("输入图中边的条数: ");
		int edges = sc.nextInt();
		System.out.println("输入图中边的起始顶点, 结束顶点和顶点之间的权值: ");
		for(int i = 0; i < edges; i++){
			int start = sc.nextInt();
			int end = sc.nextInt();
			int weight = sc.nextInt();
			graph[start][end] = weight;
			graph[end][start] = weight;
		}
		for(int i = 0; i < n; i++){
			for(int j = 0; j < n; j++){
				System.out.print(graph[i][j] + " ");
			}
			System.out.println();
		}
		dfs(0);
		sc.close();
	}
	
	private static void dfs(int cur) {
		visit[cur] = 1;
		System.out.println(cur);
		for(int i = cur; i < n; i++){
			if(visit[i] == 0 &&graph[cur][i] != 0){
				dfs(i);
			}
		}
	}
}

4. 输入数据:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值