java bfs_详解BFS和DFS及Java实现

1.图的表示

图是由顶点和边组成,图最常用的两种方法就是邻接表和邻接矩阵。这两种办法分别用表和矩阵的方式描述图中各顶点之间的联系。

2d6812a7b868

下面分别展示了两种表示上面这个图的方法:

2d6812a7b868

2.图的遍历

广度优先遍历和深度优先遍历是遍历图的两种最常用的方法,下面将详细进行介绍。

2.1 广度优先遍历(BFS)

即Breadth First Search,其主要思想是从起始点开始,将其邻近的所有顶点都加到一个队列(FIFO)中去,然后标记下这些顶点离起始顶点的距离为1.最后将起始顶点标记为已访问,今后就不会再访问。然后再从队列中取出最先进队的顶点A,也取出其周边邻近节点,加入队列末尾,将这些顶点的距离相对A再加1,最后离开这个顶点A。依次下去,直到队列为空为止。从上面描述的过程我们知道每个顶点被访问的次数最多一次(已访问的节点不会再访问),而对于连通图来说,每个顶点都会被访问。加上每个顶点的邻接链表都会被遍历,因此BFS的时间复杂度是Θ(V+E),其中V是顶点个数,E是边数,也就是所有邻接表中的元素个数。为了更好的说明这个过程,下图列出了对一个图的BFS的过程。

2d6812a7b868

代码实现:

import java.util.HashMap;

import java.util.LinkedList;

import java.util.Queue;

public class BFSDemo {

public static void main(String[] args) {

//构造各顶点

LinkedList list_s = new LinkedList();

list_s.add('w');

list_s.add('r');

LinkedList list_w = new LinkedList();

list_w.add('s');

list_w.add('i');

list_w.add('x');

LinkedList list_r = new LinkedList();

list_r.add('s');

list_r.add('v');

LinkedList list_x = new LinkedList();

list_x.add('w');

list_x.add('i');

list_x.add('u');

list_x.add('y');

LinkedList list_v = new LinkedList();

list_v.add('r');

LinkedList list_i = new LinkedList();

list_i.add('u');

list_i.add('x');

list_i.add('w');

LinkedList list_u = new LinkedList();

list_u.add('i');

list_u.add('x');

list_u.add('y');

LinkedList list_y = new LinkedList();

list_y.add('u');

list_y.add('x');

//构造图

HashMap> graph = new HashMap>();

graph.put('s', list_s);

graph.put('w', list_w);

graph.put('r', list_r);

graph.put('x', list_x);

graph.put('v', list_v);

graph.put('i', list_i);

graph.put('y', list_y);

graph.put('u', list_u);

//记录每个顶点离起始点的距离,也即最短距离

HashMap dist = new HashMap();

//遍历的起始点

char start = 's';

//调用广度优先方法

bfs(graph, dist, start);

}

private static void bfs(HashMap> graph, HashMap dist,

char start) {

Queue q = new LinkedList<>();

q.add(start);// 将s作为起始顶点加入队列

dist.put(start, 0);

int i = 0;

while (!q.isEmpty()) {

char top = q.poll();// 取出队首元素

i++;

System.out.println("The " + i + "th element:" + top + " Distance from s is:" + dist.get(top));

int d = dist.get(top) + 1;// 得出其周边还未被访问的节点的距离

for (Character c : graph.get(top)) {

if (!dist.containsKey(c))// 如果dist中还没有该元素说明还没有被访问

{

dist.put(c, d);

q.add(c);

}

}

}

}

}

运行结果:

The 1th element:s Distance from s is:0

The 2th element:w Distance from s is:1

The 3th element:r Distance from s is:1

The 4th element:i Distance from s is:2

The 5th element:x Distance from s is:2

The 6th element:v Distance from s is:2

The 7th element:u Distance from s is:3

The 8th element:y Distance from s is:3

2.2 深度优先遍历(DFS)

即Depth First Search,深度优先搜索是从起始顶点开始,递归访问其所有邻近节点,比如A节点是其第一个邻近节点,而B节点又是A的一个邻近节点,则DFS访问A节点后再访问B节点,如果B节点有未访问的邻近节点的话将继续访问其邻近节点,否则继续访问A的未访问邻近节点,当所有从A节点出去的路径都访问完之后,继续递归访问除A以外未被访问的邻近节点。具体看下图:

2d6812a7b868

代码如下:

import java.util.HashMap;

import java.util.LinkedList;

public class DFSDemo {

public static void main(String[] args) {

//构造各顶点

LinkedList list_u = new LinkedList();

list_u.add('v');

list_u.add('x');

LinkedList list_v = new LinkedList();

list_v.add('y');

LinkedList list_y = new LinkedList();

list_y.add('x');

LinkedList list_x = new LinkedList();

list_x.add('v');

LinkedList list_w = new LinkedList();

list_w.add('y');

list_w.add('z');

LinkedList list_z = new LinkedList();

//构造图

HashMap> graph = new HashMap>();

graph.put('u', list_u);

graph.put('v', list_v);

graph.put('y', list_y);

graph.put('x', list_x);

graph.put('w', list_w);

graph.put('z', list_z);

HashMap visited = new HashMap();

//调用深度优先遍历方法

dfs(graph, visited);

}

private static void dfs(HashMap> graph, HashMap visited) {

visit(graph, visited, 'u');// 为了和图中的顺序一样,我认为控制了DFS先访问u节点

visit(graph, visited, 'w');

}

//通过一个全局变量count记录了进入每个节点和离开每个节点的时间

static int count;

private static void visit(HashMap> graph, HashMap visited,

char start) {

if (!visited.containsKey(start)) {

count++;

System.out.println("The time into element " + start + ":" + count);// 记录进入该节点的时间

visited.put(start, true);

for (char c : graph.get(start)) {

if (!visited.containsKey(c)) {

visit(graph, visited, c);// 递归访问其邻近节点

}

}

count++;

System.out.println("The time out element " + start + ":" + count);// 记录离开该节点的时间

}

}

}

运行结果:

The time into element u:1

The time into element v:2

The time into element y:3

The time into element x:4

The time out element x:5

The time out element y:6

The time out element v:7

The time out element u:8

The time into element w:9

The time into element z:10

The time out element z:11

The time out element w:12

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值