【数据结构与算法】无向图的结构与遍历 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) 线性表 是一种逻辑结构,相同数据类型的 ...
随机推荐
- Graphics绘制图形
List<double> labels = form.channelData2[kp.Key]; List<double> listY = kp.Value; int labe ...
- Python+unittest+requests 接口自动化测试框架搭建 完整的框架搭建过程 实战
一.Python+unittest+requests+HTMLTestRunner 完整的接口自动化测试框架搭建_00--框架结构简解 首先配置好开发环境,下载安装Python并下载安装pycharm ...
- Spring 核心容器 IOC
目录 1. BeanFactory 2. BeanDefinition 3. BeanDefinitionReader 4 . Web IOC 容器初体验 一 .BeanFactory Spring ...
- 8css 盒子模型
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- jQuery实现论坛发帖Demo
目录 效果展示 思路 代码 改进空间 效果展示 思路 主要知识点:运用jQuery对HTML元素节点的操作(append)来添加帖子. 交互设计:用户点击页面上的"论坛发帖"按钮, ...
- VUE项目中检测网页滑动注意事项
一.this.$nextTick(function () { window.addEventListener('scroll', this.onScroll, true) ...
- CH573 CH582 CH579蓝牙从机(peripheral)例程讲解三(蓝牙服务修改)
修改服务需要对蓝牙比较熟悉的工程师去完成,否则在例程功能满足自己需求时,不建议修改,很容易改错,下面就简单介绍下如何在别的char添加一个nofify属性. step1: 给Simple Profil ...
- Go_day02
Go基础语法 流程控制 一共有三种:顺序结构,选择结构,循环结构 if语句 /* if与else if的区别: 1:if无论是否满足条件都会向下执行,直到程序结束,else if 满足一个条件就会停止 ...
- Rosetta scoring
参考:https://www.rosettacommons.org/demos/latest/tutorials/scoring/scoring 介绍 Rosetta有一个被称为ref2015的优化能 ...
- Spring设计模式——原型模式
原型模式 原型模式(Prototype Pattern),是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象. 原型模式主要适用于以下场景: 类初始化消耗资源较多 使用new生成一个对象 ...