JAVA广度优先搜索---寻找从A点到B点最短路径

本文介绍了如何使用JAVA实现广度优先搜索(BFS)算法寻找图中从A点到B点的最短路径。通过一步步地拓展搜索路径并记录步数,当队列为空或找到目标点时搜索结束。文中提供了中文版的参考实现和实际的代码示例,展示了简单的队列模拟方式。作者感叹这种简单模拟队列的方法充满了智慧,但也指出需要经常回顾以保持熟悉。

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

前言

搜索界两大基础搜索算法分别是广度优先搜索和深度优先搜索。

搜索算法可以用于寻找图的连通性。
一个普通的二维地图,从A点到B点,有两个问题。

  • 能否到达?
  • 怎样以最短的路径走到B点?

这是搜索算法能够解决的事情。

要使用广度优先搜索算法来搜索从A点到B点的最短路径

依据广度优先的原则,每走一步,都将下一步所有可能的选择入队之后,才进行下一步

结束标记:

队列为空时,搜索结束
搜索到指定结果时,搜索结束

实现功能

在一个二维地图中

  • 计算A点到B点的最少步数
  • 输出最少步数的路径

中文版参考实现

     *
     *                  A
     *                B   C
     *              D   G   E
     *            F
     * 搜索从A到F的最少步数
     * 宽度优先搜索:
     *      第一步:
     *              A入队,步数是0
     *              A为队列头
     *      第二步:
     *              查看A下一步的所有选择
     *              有B和C,所以第二步可以到达B和C,步数是1
     *              B、C入队,同时标记B和C,表示已经走过了。
     *              A已经没用了,因为A所有可能到达的点已经在队列里了,所以A出队。
     *              判断是否达到目标地点,是,结束循环。当前步数是最短步数
     *              否则继续
     *              此时队列头为B
     *      第三步:
     *              B、C是同时入队的,所以两个都要在第三步里扩展所有可能。
     *
     *              1.  查看B下一步的所有选择
     *                  有D、G
     *                  D、G入队,标记D、G
     *                  B也没用了,B出队
     *                  判断是否达到目标地点,是,结束循环。当前步数是最短步数
     *                  否则继续
     *                  此时队列头为C
     *              2.  查看C下一步的所有选择
     *                  有G、E,但是G已经标记走过了
     *                  所以只有E可选
     *                  E入队,同时标记E
     *                  C已无效,C出队
     *                  此时队列头为D
     *              合并B、C扩展出来的所有选择,有D、G、E
     *              所以第三步可以达到的是D、G、E,步数是2
     *              判断是否达到目标地点,是,结束循环。当前步数是最短步数
     *              否则继续
     *      第四步:
     *              搜索D、G、E所有的的扩展可能
     *
     *              1.  查看D下一步的所有选择
     *                  有F,F是目标,F入队,此时步数是3
     *                  D出队
     *                  判断是否达到目标地点,是,结束循环。当前步数是最短步数
     *                  发现F是目标,结束遍历。
     *
     *      A到达F的最小步数是3
     */

代码实现

/**
 * 一个5行4列的地图
 * 其中部分地方有障碍无法通过
 * 找出从(1, 1)到(4, 3)的最少步数是多少
 * 输出路径
 */
public class WalkingLabyrinth {
    static int maxLine = 6;
    static int maxRow = 5;
    static int[][] map = new int[maxLine][maxRow];
    static int[][] mark = new int[maxLine][maxRow];
    static int targetLine = 4;
    static int targetRow = 3;
    static int step = -1;
    static int[][] nextDirection = {
            {0, -1},
            {1, 0},
            {0, 1},
            {-1, 0}
    };
    public static void main(String[] args) {
        map[1][3] = 1;
        map[3][3] = 1;
        map[4][2] = 1;
        map[5][4] = 1;
        //堵住所有道路
        //map[4][4] = 1;
        //map[5][3] = 1;
        bfs(1, 1);
        System.out.print(step == -1 ? "\n没有到达" : "\n到达");
        System.out.println("目标位置: " + targetLine + "行" + targetRow + "列,步数:" + step);
    }
    public static void bfs(int startLine, int startRow) {
        mark[startLine][startRow] = 1;
        Node[] queue = new Node[maxLine * maxRow];
        int head = 0;
        int tail = 0;
        Node tNode = new Node(startLine, startRow, 0, head);
        queue[tail++] = tNode;
        int tLine, tRow;

        while (head < tail) {

            for (int i = 0; i < 4; i++) {
                tLine = queue[head].getLine() + nextDirection[i][0];
                tRow = queue[head].getRow() + nextDirection[i][1];

                if (tLine >= maxLine || tRow >= maxRow || tLine < 1 || tRow < 1) {
                    continue;
                }

                if (mark[tLine][tRow] != 1 && map[tLine][tRow] != 1) {
                    tNode = new Node(tRow, tLine, queue[head].getStep() + 1, head);
                    queue[tail++] = tNode;
                    //System.out.println("当前位置: " + tLine + "行" + tRow + "列,步数:" + queue[tail - 1].getStep());
                    mark[tLine][tRow] = 1;
                }

                if (tLine == targetLine && tRow == targetRow) {
                    step = queue[tail - 1].getStep();

                    System.out.println("经过路径:");
                    int index = tail - 1;
                    for (int j = 0; j <= step; j++) {
                        System.out.println("("+ queue[index].getLine() + "," + queue[index].getRow() +")");
                        index = queue[index].getP();
                    }
                    return;
                }
            }
            head++;
        }
        step = -1;
    }

    private static class Node {
        int row, line, step;
        int p;

        public int getP() {
            return p;
        }

        Node(int line, int row) {
            this.line = line;
            this.row = row;
        }

        Node(int row, int line, int step, int p) {
            this.row = row;
            this.line = line;
            this.step = step;
            this.p = p;
        }

        public int getRow() {
            return row;
        }

        public int getLine() {
            return line;
        }

        public int getStep() {
            return step;
        }
    }
}

结果

经过路径:
(4,3)
(5,3)
(5,2)
(5,1)
(4,1)
(3,1)
(2,1)
(1,1)

到达目标位置: 4行3列,步数:7

一点收获

原来简单模拟队列,可以简单到如此程度!!
一个数组,两个索引。

int index = tail - 1;
                    for (int j = 0; j <= step; j++) {
                        System.out.println("("+ queue[index].getLine() + "," + queue[index].getRow() +")");
                        index = queue[index].getP();
                    }

感觉我的这段代码充满了智慧恩,这是传说中的推倒(ノ*・ω・)ノ,好吧是倒推!

之前是看过的,过了不到三个月,再看跟新的一样。太久没用了,还是得日久才能熟悉。没事要瞄一眼代码留点印象。

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值