java实现无向图的深度优先搜索和广度优先搜索

本文介绍了如何使用Java实现无向图的深度优先搜索(DFS)和广度优先搜索(BFS)。通过邻接链表作为数据结构,DFS利用递归遍历所有可达顶点,呈现深度优先的搜索路径;而BFS则借助队列,按照层次顺序进行搜索。这些基础搜索算法为实现图的其他复杂算法如连通分量、最短路径和最小生成树奠定了基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先实现无向图的数据结构。

package graph;

import simpleStructure.Bag;
/**
 * 用邻接表做的图
 * 用了一个Bag数组,数组的索引是顶点,索引的内容Bag里面存放与该顶点相邻的顶点
 * @author Administrator
 *
 */
public class Graph implements GraphItf
{
    private Bag<Integer>[] adj;
    private final int vertexNum;
    private int edgeNum;
    /**
     * 构造有v个顶点的图
     * 编号从0到v-1
     * @param v
     */
    public Graph(int v)
    {
        vertexNum = v;
        adj = (Bag<Integer>[]) new Bag[v];
        for(int i = 0;i < v;i++)
        {
            adj[i] = new Bag<Integer>();
        }
    }

    @Override
    public int vertexNum()
    {
        // TODO Auto-generated method stub
        return vertexNum;
    }

    @Override
    public int edgeNum()
    {
        // TODO Auto-generated method stub
        return edgeNum;
    }

    @Override
    public void addEdge(int v, int w)
    {
        // TODO Auto-generated method stub
        adj[v].add(w);
        adj[w].add(v);
        edgeNum++;
    }

    @Override
    public Iterable<Integer> adj(int v)
    {
        // TODO Auto-generated method stub
        return adj[v];
    }
}

这里用的是邻接链表,bag是一个链表,bags是一个bag的数组,bags[x]是一个bag,bag中有x节点所连接的所有节点。
接下来实现无向图的深度优先遍历

package graph;

/**
 * 深度优先搜索
 * @author zsj
 *
 */
public class DepthFirstSearch implements SearchItf
{
    private boolean[] marked;//查看一个点是否被遍历过
    private int count;//遍历到的点的数量
    private Graph graph;//传入的图

    public DepthFirstSearch(Graph g, int s)
    {
        this.graph = g;
        marked = new boolean[g.vertexNum()];
        dfs(s);
    }

    //用递归实现的深度优先搜索
    private void dfs(int v)
    {
        if (marked[v])
            return;
        marked[v] = true;
        count++;
        for (Integer i : graph.adj(v))
        {
            dfs(i);
        }
    }

    @Override
    public boolean marked(int v)
    {
        // TODO Auto-generated method stub
        return marked[v];
    }

    @Override
    public int count()
    {
        // TODO Auto-generated method stub
        return count;
    }

}

深度优先搜索就是递归的调用dfs遍历当前顶点可达的所有顶点。
在图像上看就会呈现出走一条路走到底,再回溯,走另一条路。
下面实现广度优先搜索

package graph;

import simpleStructure.Queue;
import simpleStructure.Stack2;

/**
 * 广度优先搜索
 * @author zsj
 *
 */
public class BreadthFirstPaths implements PathsItf
{
    private GraphItf g;//传入的图
    private int s;//起始点
    private boolean[] marked;//marked[i]显示i有没有被遍历过,有的话就是true
    private int[] edgeTo;//edgeTo[i]=v说明i的父节点是v,edgeTo储存的是s广度遍历得到的路径
    private Queue<Integer> queue;//广度遍历所需要的队列

    public BreadthFirstPaths(GraphItf g, int s)
    {
        // TODO Auto-generated constructor stub
        this.g = g;
        this.s = s;
        marked = new boolean[g.vertexNum()];
        edgeTo = new int[g.vertexNum()];
        queue = new Queue<Integer>();
        bfs(s);
    }

    //使用队列实现的广度优先搜索顶点v
    private void bfs(int v)
    {
        queue.enqueue(v);
        marked[s] = true;
        while (!queue.isEmpty())
        {
            int head = queue.dequeue();
            for (int i : g.adj(head))
                if (!marked[i])
                {
                    queue.enqueue(i);
                    edgeTo[i] = head;
                    marked[i] = true;
                }
        }
    }


    @Override
    public boolean hasPathTo(int v)
    {
        // TODO Auto-generated method stub
        return marked[v];
    }

    @Override
    public Iterable<Integer> pathTo(int v)
    {
        if(!marked[v]) return null;
        Stack2<Integer> stack2 = new Stack2<Integer>();
        while (v != s)
        {
            stack2.push(v);
            v = edgeTo[v];
        }
        stack2.push(s);
        return stack2;
    }

}

这里使用队列实现广度优先搜索,而深度优先搜索是使用栈来实现。
基本过程是,先将开始点放入队列,然后从队列弹出一个元素做当前的head,将当前head所连接的没有被遍历过的点放入队列,再从队列弹出一个,如此循环,直到队列为空。
在图像上看就是一层一层的向下搜索,而不是一条路先走到底。

有向图的搜索与无向图类似并且更加简单,同样可以采用邻接链表的数据结构来实现有向图,不同的只是添加节点的时候只需要单向添加就行了,因为是单向的。

有了深度和广度优先搜索,才可以实现图上的各类算法,像连通分量,最短路径,最小生成树等等。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值