java实现BFS和DFS

转载于:https://www.jianshu.com/p/2d6812a7b868

1.图的表示

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

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

2.图的遍历

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

2.1 广度优先遍历(BFS)

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

代码实现:

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
public class BFSDemo {
  public static void main(String[] args) {
        //构造各顶点
        LinkedList<Character> list_s = new LinkedList<Character>();
        list_s.add('w');
        list_s.add('r');
        LinkedList<Character> list_w = new LinkedList<Character>();
        list_w.add('s');
        list_w.add('i');
        list_w.add('x');
        LinkedList<Character> list_r = new LinkedList<Character>();
        list_r.add('s');
        list_r.add('v');
        LinkedList<Character> list_x = new LinkedList<Character>();
        list_x.add('w');
        list_x.add('i');
        list_x.add('u');
        list_x.add('y');
        LinkedList<Character> list_v = new LinkedList<Character>();
        list_v.add('r');
        LinkedList<Character> list_i = new LinkedList<Character>();
        list_i.add('u');
        list_i.add('x');
        list_i.add('w');
        LinkedList<Character> list_u = new LinkedList<Character>();
        list_u.add('i');
        list_u.add('x');
        list_u.add('y');
        LinkedList<Character> list_y = new LinkedList<Character>();
        list_y.add('u');
        list_y.add('x');
        //构造图
        HashMap<Character, LinkedList<Character>> graph = new HashMap<Character, LinkedList<Character>>();
        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<Character, Integer> dist = new HashMap<Character, Integer>();
        //遍历的起始点
        char start = 's';
        //调用广度优先方法
        bfs(graph, dist, start);
    }    
    private static void bfs(HashMap<Character, LinkedList<Character>> graph, HashMap<Character, Integer> dist,
            char start) {
        Queue<Character> 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以外未被访问的邻近节点。具体看下图:

代码如下:

import java.util.HashMap;
import java.util.LinkedList;
public class DFSDemo {
    public static void main(String[] args) {
        //构造各顶点
        LinkedList<Character> list_u = new LinkedList<Character>();
        list_u.add('v');
        list_u.add('x');
        LinkedList<Character> list_v = new LinkedList<Character>();
        list_v.add('y');
        LinkedList<Character> list_y = new LinkedList<Character>();
        list_y.add('x');
        LinkedList<Character> list_x = new LinkedList<Character>();
        list_x.add('v');
        LinkedList<Character> list_w = new LinkedList<Character>();
        list_w.add('y');
        list_w.add('z');
        LinkedList<Character> list_z = new LinkedList<Character>();
        //构造图
        HashMap<Character, LinkedList<Character>> graph = new HashMap<Character, LinkedList<Character>>();
        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);<Character, Boolean> visited = new HashMap<Character, Boolean>();
        //调用深度优先遍历方法
        dfs(graph, visited);
    }
    private static void dfs(HashMap<Character, LinkedList<Character>> graph, HashMap<Character, Boolean> visited) {
        visit(graph, visited, 'u');// 为了和图中的顺序一样,我认为控制了DFS先访问u节点
        visit(graph, visited, 'w');
    }
    //通过一个全局变量count记录了进入每个节点和离开每个节点的时间
    static int count;
    private static void visit(HashMap<Character, LinkedList<Character>> graph, HashMap<Character, Boolean> 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
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值