【数据结构与算法】无向图的结构与遍历 BFS&DFS
1 表示无向图的数据类型
1.1 邻接矩阵
可以使用一个V*V的二维布尔矩阵,当定点v和定点w相连的时候,定义第v行第w列的值为true,否则为false。邻接矩阵不适合定点较多的情况,含有百万的顶点数的图是很常见的,V^2的空间很难得满足。
1.2 邻接表
邻接表使用一个记录当前顶点相邻顶点的链表即边表,和一个快速访问给定顶点的顶点列表即顶点表。数据类型如下:
public class Graph {
private final int V;
private int E;
private Bag<Integer>[] adj;
Graph(int V) {
this.V = V;
adj = (Bag<Integer>[]) new Bag[V];
for (int i = 0; i < V; i++)
adj[i] = new Bag<Integer>();
}
public void addEdge(int u, int v) {
adj[u].add(v);
}
public int V() {
return this.V;
}
public int E() {
return this.E;
}
public Iterable<Integer> adj(int v) {
return adj[v];
}
public String toString() {
String s = V + " vertices, " + E + " edges.\n";
for (int i = 0; i < V; i++) {
s += i + " : ";
for(int w : this.adj(i))
s += w + " ";
s += "\n";
}
return s;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int V = sc.nextInt();
int E = sc.nextInt();
Graph g = new Graph(V);
for (int i = 0; i < E; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
g.addEdge(u, v);
g.addEdge(v, u);
}
System.out.println(g);
}
}
测试输入:
13
13
0 5
4 3
0 1
9 12
6 4
5 4
0 2
11 12
9 10
0 6
7 8
9 11
5 3
输出结果
13 vertices, 0 edges.
0 : 6 2 1 5
1 : 0
2 : 0
3 : 5 4
4 : 5 6 3
5 : 3 4 0
6 : 0 4
7 : 8
8 : 7
9 : 11 10 12
10 : 9
11 : 9 12
12 : 11 9
2 深度优先搜索
DepthFirstSearch.class
2.1 DFS的递归写法
public class DepthFirstSearch {
boolean[] marked;
private int count;
DepthFirstSearch(Graph g, int s) {
marked = new boolean[g.V()];
dfs(g, s);
}
void visit(int v) {
System.out.print(v + " ");
}
void dfs(Graph g, int v) {
marked[v] = true;
visit(v);
for(int w : g.adj(v)) {
if(!marked[w]) {
dfs(g, w);
}
}
}
}
测试结果
0 6 4 5 3 2 1
2.2 ★DFS的非递归写法
非递归写法主要借助了栈,思想与二叉树的先序遍历类似:每次将栈顶出栈再将栈顶的右节点和左节点依次入栈,只不过这里需要每次入栈一个相邻未访问节点,等到全被访问才将栈顶出栈。
①首先将第一个顶点入栈,并标记为已访问。
②遍历栈顶顶点第一个未被访问过的相邻节点将其入栈,如果栈顶顶点没有未被访问过的相邻顶点则将栈顶节点出栈。
③重复执行②直至栈空。
void dfs2(Graph g, int v) {
Stack<Integer> s = new Stack<>();
s.push(v);
visit(v);
marked[v] = true;
while(!s.empty()) {
int x = s.peek();
boolean flag = false;
// 每次访问第一个未被访问的相邻节点
for(int w : g.adj(x)) {
if(!marked[w]) {
visit(w);
s.push(w);
marked[w] = true;
flag = true;
break;
}
}
// 如果不存在相邻顶点则将栈顶顶点出栈
if(!flag)
s.pop();
}
}
2.3 寻找路径
2.4 DFS寻找所有路径
3 广度优先搜索
广度优先遍历一般用于求单源最短路径。
public class BreadthFirstPaths {
private boolean[] marked;
private int[] edgeTo;
private int s;
BreadthFirstPaths(Graph g, int s) {
marked = new boolean[g.V()];
edgeTo = new int[g.V()];
this.s = s;
bfs(g, s);
}
public void bfs(Graph g, int v) {
Queue<Integer> q = new LinkedBlockingQueue<>();
q.add(v);
marked[v] = true;
while (!q.isEmpty()) {
int x = q.poll();
for (int w : g.adj(x)) {
if (!marked[w]) {
edgeTo[w] = x;
q.add(w);
marked[w] = true;
}
}
}
}
public Stack<Integer> pathTo(int v) {
Stack<Integer> s = new Stack<>();
while (v != this.s) {
s.push(v);
v = edgeTo[v];
}
s.push(v);
return s;
}
}
【数据结构与算法】无向图的结构与遍历 BFS&DFS的更多相关文章
- 【数据结构与算法】二叉树的 Morris 遍历(前序、中序、后序)
前置说明 不了解二叉树非递归遍历的可以看我之前的文章[数据结构与算法]二叉树模板及例题 Morris 遍历 概述 Morris 遍历是一种遍历二叉树的方式,并且时间复杂度O(N),额外空间复杂度O(1 ...
- 数据结构与算法实验题 9.1 K 歌 DFS+剪枝
数据结构与算法实验题 K 歌 ★实验任务 3* n 个人(标号1~ 3 * n )分成 n 组 K 歌.有 m 个 3 人组合,每个组合都对应一个分数,你能算出最大能够得到的总分数么? ★数据输入 输 ...
- 重新整理数据结构与算法(c#)—— 图的深度遍历和广度遍历[十一]
参考网址:https://www.cnblogs.com/aoximin/p/13162635.html 前言 简介图: 在数据的逻辑结构D=(KR)中,如果K中结点对于关系R的前趋和后继的个数不加限 ...
- 算法导论—无向图的遍历(BFS+DFS,MATLAB)
华电北风吹 天津大学认知计算与应用重点实验室 最后改动日期:2015/8/22 无向图的存储方式有邻接矩阵,邻接链表,稀疏矩阵等. 无向图主要包括双方面内容,图的遍历和寻找联通分量. 一.无向图的遍历 ...
- 数据结构与算法--树(tree)结构
树 二叉树 遍历原则:前序遍历是根左右, 中序遍历是左根右,后序遍历是左右根. 二叉搜索树 特点:对于树中的每个节点X,它的左子树中所有节点的值都小于X,右子树中所有节点的值都大于X. 遍历:采取二叉 ...
- 算法学习 - 图的广度优先遍历(BFS) (C++)
广度优先遍历 广度优先遍历是非经常见和普遍的一种图的遍历方法了,除了BFS还有DFS也就是深度优先遍历方法.我在我下一篇博客里面会写. 遍历过程 相信每一个看这篇博客的人,都能看懂邻接链表存储图. 不 ...
- 数据结构学习笔记05图 (邻接矩阵 邻接表-->BFS DFS、最短路径)
数据结构之图 图(Graph) 包含 一组顶点:通常用V (Vertex) 表示顶点集合 一组边:通常用E (Edge) 表示边的集合 边是顶点对:(v, w) ∈E ,其中v, w ∈ V 有向边& ...
- 图的创建和遍历(BFS/DFS)
图的表示方法主要有邻接矩阵和邻接表.其中邻接表最为常用,因此这里便以邻接表为例介绍一下图的创建及遍历方法. 创建图用到的结构有两种:顶点及弧 struct ArcNode { int vertexIn ...
- 模板 图的遍历 bfs+dfs 图的最短路径 Floyed+Dijkstra
广搜 bfs //bfs #include<iostream> #include<cstdio> using namespace std; ],top=,end=; ][]; ...
- Java数据结构和算法(一)线性结构
Java数据结构和算法(一)线性结构 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 线性表 是一种逻辑结构,相同数据类型的 ...
随机推荐
- openvas在centos中扫描单项的python实现
使用gvm_cli命令来实现 先创建一个空的配置 copy_id = '085569ce-73ed-11df-83c3-002264764cea' new_config = ''' <creat ...
- NOIP2013普及组
T1]记数问题 试计算在区间1 到n 的所有整数中,数字x(0 ≤ x ≤ 9)共出现了多少次?例如,在1到11 中,即在1.2.3.4.5.6.7.8.9.10.11中,数字1 出现了4 次. 其实 ...
- RabbitMQ身份验证、授权、访问控制
原文:https://www.rabbitmq.com/access-control.html 概述 不同的用户只能访问特定的虚拟主机.他们在每个虚拟主机中的权限也可以被限制. RabbitMQ支持两 ...
- 并发QPS公式估算
一.经典公式1: 一般来说,利用以下经验公式进行估算系统的平均并发用户数和峰值数据 1)平均并发用户数为 C = nL/T 2)并发用户数峰值 C' = C + 3*根号C C是平均并发用户数,n是l ...
- 离线安装docker和harbor
1.下载docker和harbor版本(版本自选) docker下载地址: https://download.docker.com/linux/static/stable/x86_64/ harbor ...
- 关系类处理专题之创建关系类|RelationShipClass
/// <summary> /// 存在于数据库中的数据集中 /// </summary> /// <param name="mdbPath"> ...
- Go_day05
Go基础语法 OOP面向对象 Go语言本身不是面向对象的语言,但是可以通过一些方法来模拟对象 面向对象的思维就是分类思维 继承 // 定义一个父类结构体 type Person struct { na ...
- Java-http请求工具-OkHttp用法
前言:一般Java项目后端发送请求都使用http,最近项目里面大佬建议把http都改成okhttp3(OkHttpClient).故今日记录部分常用发送方式. 代码:为了便于以后使用,这里封装一个Ok ...
- PHP 计算机码、位运算、运算符优先级
计算机码 计算机在实际存储数据的时候,是采用编码规则的(二进制编码) 计算机码存储的过程: 原码.反码和补码,数值最左边一位用来充当符号位:符号为正数为0,负数为1 原码:数据本身从十进制转换为二进制 ...
- 网络安全(中职组)-B模块:服务远程控制
任务四:服务远程控制任务环境说明:服务器场景名:20200609(关闭链接)服务器场景操作系统:未知服务器场景用户名:root服务器场景密码:Admin123 1. 通过本地PC中渗透测试平台K ...