java非递归实现图的dfs和bfs(图解+大纲清晰明了)

准备工作

图的创建

在这里插入图片描述

在这里插入图片描述

class Graph {
    //表示顶点数量
    private int V;
    //表示边的数量
    private int E;
    private Queue<Integer>[] adj;
    private boolean[] marked;
    
    //初始化图
    public Graph(int n) {
        V = n;
        E = 0;
        adj = new LinkedList[V];
        for (int i = 0; i < n; i++) {
            adj[i] = new LinkedList<>();
        }
    }
    //获取图的顶点
    public int V() {
        return V;
    }

    //获取图的边
    public int E() {
        return E;
    }

    /**
     * 添加边的方法
     *
     * @param x
     * @param y
     */
    public void add(int x, int y) {
        adj[x].offer(y);
        adj[y].offer(x);
        E++;
    }

    /**
     * 获取顶点对应的其他顶点队列
     *
     * @return
     */
    public Queue<Integer> adj(int v) {
        //直接用索引取就可以了
        return adj[v];
    }
}

广度优先遍历

看图
在这里插入图片描述

类似于二叉树的层序遍历

如果从0开始 那就是0→1→3→5→2→4

如果从1开始 那就是1→0→5→3→4→2

如果从2开始 那就是2→3→4→0→5→1

如果从3开始 那就是3→0→5→2→1→4

也就是说 先从顶点开始访问子节点 再访问子节点的兄弟节点 直到没有兄弟节点了

展开 顶点第一次访问的子节点

然后再访问兄弟节点 直到遍历完毕

所以我们需要在使用图的基础上

新增一个标记哪个节点被访问过的marked布尔数组

维护一个队列来存放进出的元素


思维导图大纲

看下大纲吧
在这里插入图片描述
核心思路截取一下
在这里插入图片描述

/**
 * 与深度遍历不同的是 广度优先需要维护一个队列
 */
class GraphRangeSearch {
    int count;
    boolean[] marked;
    Queue<Integer> queue;

    public GraphRangeSearch(Graph G, int s) {
        marked = new boolean[G.V()];
        //这里使用的是链表当队列
        queue=new LinkedList<>();
        //初始化完毕 打印遍历顺序
        bfs(G,s);
    }

    private void bfs(Graph G, int v) {
        //先标记该顶点 表示已搜索过
        marked[v]=true;
        //队列中加入该元素
        queue.offer(v);
        while (!queue.isEmpty()) {
            //取出队列的第一个元素
            Integer first = queue.poll();
            //取出一个元素 数量++
            count++;
            //遍历first的领接表 w为邻接表的第一个元素 然后是第二个 直到遍历完毕
            for (Integer w : G.adj(first)) {
                //若w没有被搜索过
                if (!marked[w]) {
                    //将该元素也放入队列
                    queue.offer(w);
                    //同时标记该元素
                    marked[w]=true;
                }
            }
            //顺便打印出元素遍历的顺序
            System.out.print(first+"  ");
        }
    }
    //返回被搜索过的顶点标记
    public boolean marked(int s) {
        return marked[s];
    }

    //获取相连的数量
    public int getCount() {
        return count;
    }
}

测试

public static void main(String[] args) {
        //准备Graph对象
        Graph G = new Graph(6);
        G.add(0,1);
        G.add(0,3);
        G.add(1,5);
        G.add(3,5);
        G.add(3,2);
        G.add(5,4);
        G.add(2,4);

        GraphRangeSearch search = new GraphRangeSearch(G, 0);
        System.out.println();
        System.out.println("总数为"+search.count);
    }

在这里插入图片描述
对照一下在这里插入图片描述


深度优先遍历

在这里插入图片描述

与广度优先不同的是 他是一个节点走到底 走不动了 再回去走其他路线
比如从0开始走 那就是0→1→5→4→2→3

但是注意 深度优先的走法有很多种 不一定是我这种走法

明白思路就可以了

思维导图大纲

在这里插入图片描述

只要把栈换成是队列 就可以完成了
在这里插入图片描述

class GraphDeepSearch {
    int count;
    boolean[] marked;
    Stack<Integer> stack;

    public GraphDeepSearch(Graph G, int s) {
        marked = new boolean[G.V()];
        stack=new Stack<>();
        dfs(G, s);
    }

    /**
     * 深度遍历
     * @param G
     * @param s
     */
    private void dfs(Graph G, int s) {
        //标记为已搜索
        marked[s]=true;
        //顶点加入栈中
        stack.push(s);
        //当栈不为空
        while (!stack.isEmpty()) {
            //弹出第一个元素
            Integer first = stack.pop();
            //相连数量++
            count++;
            //遍历first的领接表
            for (Integer w : G.adj(first)) {
                //标记w为已搜索
                if (!marked[w]) {
                    //弹出元素
                    stack.push(w);
                    //w标记为已搜索
                    marked[w] = true;
                }
            }
            System.out.print(first+"  ");
        }
    }

    public boolean marked(int v) {
        return marked[v];
    }
    public int count() {
        return count;
    }
}

测试

public static void main(String[] args) {
        //准备Graph对象
        Graph G = new Graph(6);
        G.add(0,1);
        G.add(0,3);
        G.add(1,5);
        G.add(3,5);
        G.add(3,2);
        G.add(5,4);
        G.add(2,4);

        GraphDeepSearch search = new GraphDeepSearch(G, 0);
        System.out.println();
        System.out.println("总数为"+search.count);
    }

在这里插入图片描述在这里插入图片描述

完整代码放上




public class Test {
    public static void main(String[] args) {
        //准备Graph对象
        Graph G = new Graph(6);
        G.add(0,1);
        G.add(0,3);
        G.add(1,5);
        G.add(3,5);
        G.add(3,2);
        G.add(5,4);
        G.add(2,4);

        GraphDeepSearch search = new GraphDeepSearch(G, 0);
        System.out.println();
        System.out.println("总数为"+search.count);
    }
}
class Graph {
    //表示顶点数量
    private int V;
    //表示边的数量
    private int E;
    private Queue<Integer>[] adj;
    private boolean[] marked;

    //初始化图
    public Graph(int n) {
        V = n;
        E = 0;
        adj = new LinkedList[V];
        for (int i = 0; i < n; i++) {
            adj[i] = new LinkedList<>();
        }
    }
    //获取图的顶点
    public int V() {
        return V;
    }

    //获取图的边
    public int E() {
        return E;
    }

    /**
     * 添加边的方法
     *
     * @param x
     * @param y
     */
    public void add(int x, int y) {
        adj[x].offer(y);
        adj[y].offer(x);
        E++;
    }

    /**
     * 获取顶点对应的其他顶点队列
     *
     * @return
     */
    public Queue<Integer> adj(int v) {
        //直接用索引取就可以了
        return adj[v];
    }
}


/**
 * 与深度遍历不同的是 广度优先需要维护一个队列
 */
class GraphRangeSearch {
    int count;
    boolean[] marked;
    Queue<Integer> queue;


    public GraphRangeSearch(Graph G, int s) {
        marked = new boolean[G.V()];
        queue=new LinkedList<>();
        bfs(G,s);
    }

    private void bfs(Graph G, int v) {
        //先标记该顶点 表示已搜索过
        marked[v]=true;
        //队列中加入该元素
        queue.offer(v);
        while (!queue.isEmpty()) {
            //取出队列的第一个元素
            Integer first = queue.poll();
            //取出一个元素 数量++
            count++;
            //遍历first的领接表 w为邻接表的第一个元素 然后是第二个 直到遍历完毕
            for (Integer w : G.adj(first)) {
                //若w没有被搜索过
                if (!marked[w]) {
                    //将该元素也放入队列
                    queue.offer(w);
                    //同时标记该元素
                    marked[w]=true;
                }
            }
            //顺便打印出元素遍历的顺序
            System.out.print(first+"  ");
        }
    }
    //返回被搜索过的顶点标记
    public boolean marked(int s) {
        return marked[s];
    }

    //获取相连的数量
    public int getCount() {
        return count;
    }
}


class GraphDeepSearch {
    int count;
    boolean[] marked;
    Stack<Integer> stack;

    public GraphDeepSearch(Graph G, int s) {
        marked = new boolean[G.V()];
        stack=new Stack<>();
        dfs(G, s);
    }

    /**
     * 深度遍历
     * @param G
     * @param s
     */
    private void dfs(Graph G, int s) {
        //标记为已搜索
        marked[s]=true;
        //顶点加入栈中
        stack.push(s);
        //当栈不为空
        while (!stack.isEmpty()) {
            //弹出第一个元素
            Integer first = stack.pop();
            //相连数量++
            count++;
            //遍历first的领接表
            for (Integer w : G.adj(first)) {
                //标记w为已搜索
                if (!marked[w]) {
                    //弹出元素
                    stack.push(w);
                    //w标记为已搜索
                    marked[w] = true;
                }
            }
            System.out.print(first+"  ");
        }
    }

    public boolean marked(int v) {
        return marked[v];
    }
    public int count() {
        return count;
    }
}

ps:大海上最自由的才是海贼王 -----王路飞

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值