Java数据结构----图--深度优先遍历BFS和广度优先遍历DFS

一、图的遍历

广度优先搜索BFS( Breadth-first search) 算法思想
(1)顶点v入队列。
(2)当队列非空时则继续执行,否则算法结束。
(3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。
(4)查找顶点v的第一个邻接顶点col。
(5)若v的邻接顶点col未被访问过的,则col入队列。
(6)继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。

深度优先搜索DFS(depth-first search) 算法思想:
(1)Start 顶点 v选择一个与v相邻的未被访问的顶点w
(2)并从w出发以深度优先搜索
(3)若一个顶点u的所有相邻顶点都被访问过了,则退回到最近被访问过、且有未被访问的w顶点!!!
(4)然后从w出发继续进行深度优先搜索
(5)当从任何已经访问的顶点出发,不再有未访问的顶点时,搜索终止

图的深度优先遍历:1->2->4->6->5->3
图的广度优先遍历:1->2->3->4->5->6

具体实现代码如下:

public class GraphByMatrix {
    public static final boolean UNDIRECTED_GRAPH = false;//无向图标志
    public static final boolean DIRECTED_GRAPH = true;//有向图标志

    public static final boolean ADJACENCY_MATRIX = true;//邻接矩阵实现
    public static final boolean ADJACENCY_LIST = false;//邻接表实现

    public static final int MAX_VALUE = Integer.MAX_VALUE;
    private boolean graphType;
    private boolean method;
    private int vertexSize;
    private int matrixMaxVertex;

    //存储所有顶点信息的一维数组
    private Object[] vertexesArray;
    //存储图中顶点之间关联关系的二维数组,及边的关系
    private int[][] edgesMatrix;

    // 记录第i个节点是否被访问过
    private boolean[] visited;

    /**
     * @param graphType 图的类型:有向图/无向图
     * @param method    图的实现方式:邻接矩阵/邻接表
     */
    public GraphByMatrix(boolean graphType, boolean method, int size) {
        this.graphType = graphType;
        this.method = method;
        this.vertexSize = 0;
        this.matrixMaxVertex = size;

        if (this.method) {
            visited = new boolean[matrixMaxVertex];
            vertexesArray = new Object[matrixMaxVertex];
            edgesMatrix = new int[matrixMaxVertex][matrixMaxVertex];

            //对数组进行初始化,顶点间没有边关联的值为Integer类型的最大值
            for (int row = 0; row < edgesMatrix.length; row++) {
                for (int column = 0; column < edgesMatrix.length; column++) {
                    edgesMatrix[row][column] = MAX_VALUE;
                }
            }

        }
    }

    /**
     * 深度优先搜索DFS(depth-first search),递归
     */
    public void DFS() {
        //这里是从第一上添加的顶点开始搜索
        DFS(vertexesArray[0]);
    }

    public void DFS(Object obj) {
        int index = -1;
        for (int i = 0; i < vertexSize; i++) {
            if (vertexesArray[i].equals(obj)) {
                index = i;
                break;
            }
        }
        if (index == -1) {
            throw new NullPointerException("没有这个值: " + obj);
        }

        for (int i = 0; i < vertexSize; i++) {
            visited[i] = false;
        }

        //这里要想清楚,不能放下面if else的后面!
        traverse(index);

        //graphType为true为有向图
        if (graphType) {
            for (int i = 0; i < vertexSize; i++) {
                if (!visited[i])
                    traverse(i);
            }
        }

    }

    // 深度优先就是由开始点向最深处遍历,没有了就回溯到上一级顶点
    private void traverse(int i) {
        visited[i] = true;
        System.out.print(vertexesArray[i] + " ");

        //由于是递归,如果j=-1,该方法仍然会运行,会回溯到上一级顶点!!!
        for (int j = firstAdjVex(i); j >= 0; j = nextAdjVex(i, j)) {
            if (!visited[j]) {
                traverse(j);
            }
        }

    }

    /**
     * 广度优先遍历算法 Breadth-first search(非递归)
     */
    public void BFS() {
        // LinkedList实现了Queue接口 FIFO
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int i = 0; i < vertexSize; i++) {
            visited[i] = false;
        }

        //这个循环是为了确保每个顶点都被遍历到
        for (int i = 0; i < vertexSize; i++) {
            if (!visited[i]) {
                queue.add(i);
                visited[i] = true;
                System.out.print(vertexesArray[i] + " ");

                while (!queue.isEmpty()) {
                    int row = queue.remove();

                    for (int k = firstAdjVex(row); k >= 0; k = nextAdjVex(row, k)) {
                        if (!visited[k]) {
                            queue.add(k);
                            visited[k] = true;
                            System.out.print(vertexesArray[k] + " ");
                        }
                    }

                }
            }
        }
    }

    private int firstAdjVex(int row) {
        for (int column = 0; column < vertexSize; column++) {
            if (edgesMatrix[row][column] == 1)
                return column;
        }
        return -1;
    }

    private int nextAdjVex(int row, int k) {
        for (int j = k + 1; j < vertexSize; j++) {
            if (edgesMatrix[row][j] == 1)
                return j;
        }
        return -1;
    }

    /*********************************************************************/
    // 深度非递归遍历
    public void DFS2() {
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < vertexSize; i++) {
            visited[i] = false;
        }
        for (int i = 0; i < vertexSize; i++) {
            if (!visited[i]) {
                stack.add(i);
                // 设置第i个元素已经进栈
                visited[i] = true;
                while (!stack.isEmpty()) {
                    int j = stack.pop();
                    System.out.print(vertexesArray[j] + " ");

                    for (int k = lastAdjVex(j); k >= 0; k = lastAdjVex(j, k)) {
                        if (!visited[k]) {
                            stack.add(k);
                            visited[k] = true;
                        }
                    }
                }
            }
        }
    }

    // 最后一个
    public int lastAdjVex(int i) {
        for (int j = vertexSize - 1; j >= 0; j--) {
            if (edgesMatrix[i][j] == 1)
                return j;
        }
        return -1;
    }

    // 上一个
    public int lastAdjVex(int i, int k) {
        for (int j = k - 1; j >= 0; j--) {
            if (edgesMatrix[i][j] == 1)
                return j;
        }
        return -1;
    }

    public boolean addVertex(Object val) {
        assert (val != null);
        vertexesArray[vertexSize] = val;
        vertexSize++;
        return true;
    }


    public boolean addEdge(int vnum1, int vnum2) {
        assert (vnum1 >= 0 && vnum2 >= 0 && vnum1 != vnum2);

        //有向图
        if (graphType) {
            edgesMatrix[vnum1][vnum2] = 1;

        } else {
            edgesMatrix[vnum1][vnum2] = 1;
            edgesMatrix[vnum2][vnum1] = 1;
        }
        return true;
    }

}
测试:

<pre name="code" class="java">    @Test
    public void test3() {
        GraphByMatrix g = new GraphByMatrix(Graph.DIRECTED_GRAPH, Graph.ADJACENCY_MATRIX, 6);
        g.addVertex("1");
        g.addVertex("2");
        g.addVertex("3");
        g.addVertex("4");
        g.addVertex("5");
        g.addVertex("6");

        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 3);
        g.addEdge(1, 4);
        g.addEdge(2, 1);
        g.addEdge(2, 4);
        g.addEdge(3, 5);
        g.addEdge(2, 4);
        g.addEdge(4, 5);

        g.DFS();
        System.out.println();
        g.DFS2();
        System.out.println();
        g.DFS("2");

        System.out.println();
        g.BFS();
    }

 1 2 4 6 5 3 

1 2 4 6 5 3
2 4 6 5 1 3
1 2 3 4 5 6

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
二叉树的广度优先遍历BFS)可以使用队列来实现,具体步骤如下: 1. 创建一个空队列,并将根节点入队。 2. 当队列不为空时,执行以下操作: - 出队一个节点,将其值存储或打印。 - 将出队节点的左子节点入队(如果存在)。 - 将出队节点的右子节点入队(如果存在)。 3. 重复步骤2,直到队列为空。 下面是一个Python实现的示例代码: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def bfs(root): if not root: return [] result = [] queue = [root] while queue: node = queue.pop(0) result.append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) return result ``` 对于深度优先遍历DFS),有两种常用的方法:前序遍历、中序遍历和后序遍历。下面以前序遍历为例进行解释。 前序遍历的顺序是:根节点 -> 左子树 -> 右子树。具体实现步骤如下: 1. 创建一个空列表,用于存储遍历结果。 2. 定义一个辅助函数,接收一个节点作为参数: - 若节点为空,返回。 - 将节点的值存储或打印。 - 递归调用辅助函数遍历节点的左子树。 - 递归调用辅助函数遍历节点的右子树。 3. 调用辅助函数,将根节点作为参数传入。 下面是一个Python实现的示例代码: ```python def dfs(root): if not root: return [] result = [] def helper(node): if not node: return result.append(node.val) helper(node.left) helper(node.right) helper(root) return result ``` 这样,你就可以使用这两个函数来实现二叉树的广度优先遍历深度优先遍历了。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值