深度优先搜索DFS即Depth First Search。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。广度优先搜索BFS是Breadth First Search。所有因为展开节点而得到的子节点都会被加进一个先进先出的队列中。

DFS/BFS搜索算法分析定理一:深度优先搜索标记与起点连通的所有顶点所需的时间和顶点的度数之和成正比。

假设我们有两个点v和w,在一张图中,当v先访问到w时,v-w这条边从未检查的状态变为已检查,此时这条边访问了一次。当w访问v时,w-v这条边又被检查一次,但是发现已经被检查,此时这条边被访问了两次。除此之外,不可能再有其他情况导致v-w(w-v)这条边被访问。所以可得,图中每条边会被访问两次,边×2 = 顶点 Σ 度数 (各顶点度数之和)。所以成正比。定理二:一般的,使用深度优先搜索能解决的问题都可转化为广度优先搜索解决。

深度优先搜索的优点在于:递归易于理解、简单。但是深度优先搜索并没有明确的目的性,而广度优先搜索按照由近及远的顺序搜索,在很多情况下能找出最优解,而且循环的效率高于递归,并没有栈溢出的风险。在稀疏图中广度优先搜索的效率更是快过深度优先搜索很多,稠密图相差无几。在不一定需要广度优先搜索的情况下,我们可以尽量使用深度优先搜索。定理三:在使用邻接表作为图记录方法时,深度优先搜索与广度优先搜索时间复杂度均为O(V+E)。

访问元素所需的时间主要取决于图数据的记录方法,无论是深度优先搜索或是广度优先搜索,都需要检查整张图后才能计算完毕,耗时的主要部分取决于记录方式,在使用邻接矩阵作为记录数据的方法时,复杂度为O(n2),而邻接表中只有(顶点+边数×2)的数据,我们只需要执行其中一半的边数,另一半可由检查免除运算。所以,在使用邻接表作为图记录方法时,DFS与BFS时间复杂度均为O(V+E)。

基本数据结构——图类

深度优先算法和广度优先算法是基于图论的算法。在实现应用之前,先实现基本的无向图类数据结构。

Graph类用V定义定点,E定义边,LinkedList[ ]定义邻接表。package Graph;

import java.util.LinkedList;

public class Graph {

private final int V;

private int E;

private LinkedList[] adj;

public Graph(int V) {

this.V = V;

this.E = 0;

adj = (LinkedList[]) new LinkedList[V];

for (int v = 0; v < V; v++)

adj[v] = new LinkedList<>();

}

public int V() {

return V;

}

public int E() {

return E;

}

public void addEdge(int v, int w) {

adj[v].add(w);

adj[w].add(v);

E++;

}

public LinkedList adj(int v) {

return adj[v];

}

public int degree(int v,Graph g){

int count = 0;

for(int s : adj(v))

count++;

return count;

}

}

Graph类中的泛型数组

需要说明的是:这里虽然仅仅声明了泛型数组、用普通数组类型转化来实现,但也存在安全隐患。

类似下面的程序,编译通过但是内容出错,因为泛型在运行期被擦除,Object数组类间进行赋值不报错。public static void main(String[] args) {

LinkedList[] adj;

adj = (LinkedList[]) new LinkedList[5];

Object o = adj;

Object[] oa = (Object[]) o;

List li = new LinkedList<>();

li.add("s");

oa[0] = li;

System.out.println(adj[0]);

}

这种情况需要了解,但是这篇文章主要介绍算法,这部分不过多讨论。谨在此列出出错的可能性。

连通问题package Graph;

import java.util.ArrayDeque;

import java.util.Queue;

public class Connected {

private Graph g;

private boolean[] marked;

private int count;

public Connected(Graph g) {

this.g = g;

marked = new boolean[g.V()];

}

/**

* DFS算法计算连通结点

*

* @param s

* 起点

*/

public void DFS(int s) {

marked[s] = true;

count++;

for (int w : g.adj(s))

if (!marked[w])

DFS(w);

}

/**

* BFS算法计算连通结点

*

* @param s

* 起点

*/

public void BFS(int s) {

Queue q = new ArrayDeque<>();

q.add(s);

marked[s] = true;

count++;

while (!q.isEmpty()) {

for (int w : g.adj(q.poll()))

if (!marked[w]) {

marked[w] = true;

count++;

q.add(w);

}

}

}

/**

* 初始化marked标记数组状态

*/

public void cleanMarked() {

for (boolean b : marked)

b = false;

}

/**

* 返回该起点总连通结点数

*

* @return 连通结点数

*/

public int count() {

return count;

}

/**

* 判断一个结点是否被连通

*

* @param v

* 判断结点

* @return 连通状态

*/

public boolean isMarked(int v) {

return marked[v];

}

}

单点路径存在问题package Graph;

import java.util.ArrayDeque;

import java.util.Queue;

import java.util.Stack;

public class Paths {

private Graph g;

private boolean[] marked;

private int[] edgeTo;

public Paths(Graph g) {

this.g = g;

marked = new boolean[g.V()];

edgeTo = new int[g.V()];

}

/**

* DFS算法计算单点路径问题

*

* @param s

* 起点

*/

public void DFS(int s) {

marked[s] = true;

for (int w : g.adj(s))

if (!marked[w]) {

edgeTo[w] = s;

DFS(w);

}

}

/**

* 初始化marked标记数组状态

*/

public void cleanMarked() {

for (boolean b : marked)

b = false;

}

/**

* 判断一个结点是否被连通

*

* @param v

* 判断结点

* @return 连通状态

*/

public boolean isMarked(int v) {

return marked[v];

}

/**

* 是否存在从s到v的路径,默认调用深度优先,可以选择广度优先

*

* @param s

* 起点

* @param v

* 终点

* @return 存在状态

*/

public boolean hasPathTo(int s, int v) {

DFS(s);

if (isMarked(v))

return true;

return false;

}

}

单点最短路径package Graph;

import java.util.ArrayDeque;

import java.util.Queue;

import java.util.Stack;

public class Paths {

private Graph g;

private boolean[] marked;

private int[] edgeTo;

public Paths(Graph g) {

this.g = g;

marked = new boolean[g.V()];

edgeTo = new int[g.V()];

}

/**

* DFS算法计算单点路径问题

*

* @param s

* 起点

*/

public void DFS(int s) {

marked[s] = true;

for (int w : g.adj(s))

if (!marked[w]) {

edgeTo[w] = s;

DFS(w);

}

}

/**

* BFS算法计算单点最短路径问题

*

* @param s

* 起点

*/

public void BFS(int s) {

Queue q = new ArrayDeque<>();

q.add(s);

marked[s] = true;

while (!q.isEmpty()) {

for (int w : g.adj(q.poll()))

if (!marked[w]) {

marked[w] = true;

edgeTo[w] = s;

q.add(w);

}

}

}

/**

* 初始化marked标记数组状态

*/

public void cleanMarked() {

for (boolean b : marked)

b = false;

}

/**

* 判断一个结点是否被连通

*

* @param v

* 判断结点

* @return 连通状态

*/

public boolean isMarked(int v) {

return marked[v];

}

/**

* 是否存在从s到v的路径,默认调用深度优先,可以选择广度优先

*

* @param s

* 起点

* @param v

* 终点

* @return 存在状态

*/

public boolean hasPathTo(int s, int v) {

DFS(s);

// BFS(v);

if (isMarked(v))

return true;

return false;

}

/**

* 输出最短路径

*

* @param s

* 起点

* @param v

* 终点

*/

public void pathTo(int s, int v) {

if (!hasPathTo(s, v))

return;

BFS(s);

// DFS(s); 但深度优先可能不是最短路径

Stack sta = new Stack<>();

sta.push(v);

for (int i = v; i != s; i = edgeTo[i])

sta.push(edgeTo[i]);

while (!sta.isEmpty())

System.out.println(sta.pop() + " ");

}

}

连通分量计算package Graph;

public class ConnectedComp {

private Graph g;

private boolean[] marked;

private int count;

private int[] id;

public ConnectedComp(Graph g) {

this.g = g;

id = new int[g.V()];

marked = new boolean[g.V()];

}

/**

* 调用方法,便利全部结点判断分量数

*/

public void DFS() {

for (int s = 0; s < g.V(); s++) {

if (!marked[s]) {

DFS(s);

count++;

}

}

}

/**

* DFS算法计算连通结点

*

* @param s

* 起点

*/

private void DFS(int s) {

marked[s] = true;

id[s] = count;

for (int w : g.adj(s))

if (!marked[w])

DFS(w);

}

/**

* 初始化marked标记数组状态

*/

public void cleanMarked() {

for (boolean b : marked)

b = false;

}

/**

* 返回该图总分量数目

*

* @return 分量数

*/

public int count() {

return count;

}

/**

* 返回该节点属于第几个分量

*

* @param s

* 判断结点

* @return 分量组数

*/

public int id(int s) {

return id[s];

}

}

无环图问题package Graph;

public class Cycle {

private Graph g;

private boolean[] marked;

private boolean hasCycle;

public Cycle(Graph g) {

this.g = g;

marked = new boolean[g.V()];

for(int s=0;s

if(!marked[s])

DFS(s,s);

}

/**

* DFS算法计算无环图问题

*

* @param s

* 起点

*/

public void DFS(int s, int v) {

marked[s] = true;

for (int w : g.adj(s))

if (!marked[w])

DFS(w, s);

else if (w != v)

hasCycle = true;

}

/**

* 初始化marked标记数组状态

*/

public void cleanMarked() {

for (boolean b : marked)

b = false;

}

/**

* 判断是否有环

*

* @return 判断结果

*/

public boolean hasCycle() {

return hasCycle;

}

}

二分图双色问题package Graph;

public class TwoColor {

private Graph g;

private boolean[] color;

private boolean[] marked;

private boolean isTwoColor;

public TwoColor(Graph g) {

this.g = g;

marked = new boolean[g.V()];

color = new boolean[g.V()];

isTwoColor = true;

for(int s=0;s

if(!marked[s])

DFS(s);

}

/**

* DFS算法计算二分图问题

*

* @param s

* 起点

*/

public void DFS(int s) {

marked[s] = true;

for (int w : g.adj(s))

if (!marked[w]) {

color[w] = !color[s];

DFS(w);

} else if (color[w] == color[s])

isTwoColor = false;

}

/**

* 初始化marked标记数组状态

*/

public void cleanMarked() {

for (boolean b : marked)

b = false;

}

/**

* 判断是否为二分图

*

* @return 判断结果

*/

public boolean isTwoColor() {

return isTwoColor;

}

}

java bfs dfs_java优先搜索(DFS/BFS)实际应用相关推荐

  1. 03 优先搜索(dfs bfs)、最小生成树(笛卡尔 prime)、两点最短路径(迪杰斯特拉 Floyd)

    #include<bits/stdc++.h> using namespace std; void bfs(){for(int i=1;i<=n;i++)v[i]=0;queue&l ...

  2. 算法笔记01——深度优先搜索(DFS)/宽度优先搜索(BFS)

    深度优先搜索(DFS) 从某个状态开始,不断地转移状态直到无法转移,然后回退到前一步的状态,继续转移到其他状态,如此不断重复,直至找到最终的解.深度优先搜索从最开始的状态出发,遍历所有可以到达的状态. ...

  3. 【BFS宽度优先搜索】

    一.求所有顶点到s顶点的最小步数   1 //BFS宽度优先搜索 2 #include<iostream> 3 using namespace std; 4 #include<que ...

  4. 层层递进——宽度优先搜索(BFS)

    问题引入 我们接着上次"解救小哈"的问题继续探索,不过这次是用宽度优先搜索(BFS). 注:问题来源可以点击这里 http://www.cnblogs.com/OctoptusLi ...

  5. 图/树——宽度优先搜索(BFS)

    转载 宽度优先搜索(BFS, Breadth First Search)是一个针对图和树的遍历算法.发明于上世纪50年代末60年代初,最初用于解决迷宫最短路径和网络路由等问题. 对于下面的树而言,BF ...

  6. C++ 算法篇 广度(宽度)优先搜索(BFS)

    广度优先遍历 广度优先遍历(Breadth_First_Search),又称为广度优先搜索,简称BFS. 图的BFS类似于树的层序遍历. 广度优先遍历 如图将左边的图变形,得到右边的图,然后一层一层的 ...

  7. [Leetcode][第130题][JAVA][被围绕的区域][DFS][BFS]

    [问题描述][中等] [解答思路] 1. 深度优先搜索 使用深度优先搜索实现标记操作.在下面的代码中,我们把标记过的字母 O 修改为字母 A. 复杂度 class Solution {int[] dx ...

  8. 搜索入门之BFS宽度优先搜索

    基础搜索入门BFS BFS全称宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型.Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽 ...

  9. POJ-2488 A Knights Journey-深度优先搜索DFS

    POJ-2488 A Knights Journey-深度优先搜索 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37974 A ...

最新文章

  1. python 自己写个调试工具
  2. 基于OpenCV调整图像的对比度和亮度
  3. c++中的explicit关键字
  4. element-ui多选框模糊搜索输入文字闪动问题
  5. php设计模式之单例模式 1
  6. 朋友圈发送照片泄露位置?微信:P 完再发!
  7. java引用微信支付的p12证书文件
  8. VUE3.0引入本地js文件
  9. 自然语言处理——用逻辑回归来实现情绪识别
  10. 年底一大波“优化”来了
  11. 高级API 快速入门之第八章 多线程02
  12. Apache Flink 在双十一流量洪峰下的最佳实践
  13. 计算机视觉中的多视图几何<Part0—基础知识:射影几何、变换和估计>(3)
  14. 手机信号强度大小的意义
  15. .pcd文件转换为.ply文件
  16. PS学习-----------图层锁定的解决办法
  17. 支持DISTINCT的通用分页存储过程(SQL2005)
  18. 单电源运放和双电源运放的区别
  19. 前端使用xlsx.core.min.js读取excel内容
  20. Windows:打印为PDF(PDF转换器)

热门文章

  1. TODO算子-双Value类型的操作
  2. zookeeper观察者模式设计实例
  3. html select 事件 jquery,通过jquery触发select自身的change事件
  4. windows nginx 停止和启动_nginx在window与linux中启动、停止、与关闭
  5. C++中数组、链表list、容器map/vector的区别
  6. redis源码剖析(2):基础数据结构ADLIST
  7. 大数据系列2-liunx基础-1操作系统介绍
  8. 指数分布的定义形式及应用
  9. cvs 文件如何解析?
  10. 用rplidar建图 运行rbx1_nav/gmapping_demo.launch报错