迪杰斯特拉-BFS-A* 算法小记

目录

1.迪杰斯特拉算算法

2.BFS算法

  2.1 BFS( Breadth First Search )广度搜索算法

2.2 回看迪杰特斯拉算法

3.A-star算法


1.迪杰斯特拉算算法

        简称迪算法。

        功能:求单点到其他定点的最短距离,同时也能构造最短路径。注意,虽然最短距离只有一个,但是最短路径可有多条,该算法只能找到其中的一条。

        实现代码:

    /**
     * 找最短路径和最短距离
     * 还可以写成广度搜索+优先级队列来优化
     *
     * @param graph            路径网
     * @param start            开始节点
     * @param pathMatrix       从start出发,到每个节点的最短路径
     * @param shortestDistance 从start到每个节点的最短距离
     */
    public void shortestPath(int[][] graph, int start, boolean[][] pathMatrix, int[] shortestDistance) {

        boolean[] finished = new boolean[graph.length];

        for (int i = 0; i < graph.length; i++) {
            finished[i] = false;
            shortestDistance[i] = graph[start][i];
            pathMatrix[i] = new boolean[graph.length];
            if (shortestDistance[i] < MAX_VALUE) {
                pathMatrix[i][start] = true;
                pathMatrix[i][i] = true;
            }
        }

        finished[start] = true; //以计算的最短路径的集合
        shortestDistance[start] = 0;
        for (int i = 1; i < graph.length; i++) {

            //先找到这一次待加入的节点;
            // 可以用优先级队列来优化
            int minIndex = 0;
            int min = MAX_VALUE;
            for (int j = 0; j < shortestDistance.length; j++) {
                if (!finished[j] && shortestDistance[j] < min) {
                    min = shortestDistance[j];
                    minIndex = j;
                }

            }
            //找到后,把它标志位为已经入节点
            finished[minIndex] = true;

            for (int j = 0; j < graph.length; j++) {
                if (!finished[j]) {
                    int newDistance = graph[minIndex][j] + min; //如果用Integer.MAX_VALUE表示没有边-无穷大,则这里newDistance会移出为负值,而导致
                    //下面的判断成立而进入if语句。
                    if (newDistance < shortestDistance[j]) {
                        shortestDistance[j] = newDistance;
                        pathMatrix[j] = Arrays.copyOf(pathMatrix[minIndex], pathMatrix[j].length);
                        pathMatrix[minIndex][j] = true; //加上这最后一条(minIndex,j)
                    }
                }
            }
        }
    }

2.BFS算法

  2.1 BFS( Breadth First Search )广度搜索算法

        和树中的层次优先遍历是一样的。 

frontier = Queue()      //前沿队列
frontier.put(start)     //start节点入队
reached = set()        
reached.add(start)      //start节点为已访问

while not frontier.empty():
   current = frontier.get()
   for next in graph.neighbors(current):     //current节点的临近节点,即下一层
      if next not in reached:
         frontier.put(next)
         reached.add(next)

2.2 回看迪杰特斯拉算法

        很明显,迪算法也是可以改成这种广度搜索,但是迪算法不但找到了路径,还完成了最短距离。迪算法在改成广度搜索的时候,队列中的元素的距离是不一样的,预期遍历队列来求最小值,不如直接用优先级队列,该O(n)算法为O(logn),算是一种优化。而最初我就是冲着这个优化来学习这个算法的。        

    /**
     * 迪杰特斯拉算法的优先级优化算法
     *
     * @param graph 节点图
     * @param start 开始节点
     * @return shortestDistance 输出最短路径
     */
    public int[] shortestPathWithPriorityQueue(int[][] graph, int start) {

        int[] shortestDistance = new int[graph.length];

        PriorityQueue<NodeAndWeight> frontierPriorityQueue = new PriorityQueue<>();
        frontierPriorityQueue.add(new NodeAndWeight(start, graph[start][start]));
        boolean[] reached = new boolean[graph.length];
        reached[start] = true;
        // 初始化最短距离数组
        for (int i = 0; i < shortestDistance.length; i++) {
            shortestDistance[i] = MAX_VALUE;
        }
        shortestDistance[start] = 0;

        while (!frontierPriorityQueue.isEmpty()) {
            // currentNode 当前离start节点最近的为访问到的节点
            NodeAndWeight currentNode = frontierPriorityQueue.poll();
            reached[currentNode.node] = true;
            for (int i = 0; i < graph[currentNode.node].length; i++) {
                int latestDistance = shortestDistance[currentNode.node] + graph[currentNode.node][i];
                if (!reached[i] && latestDistance < shortestDistance[i]) {
                    shortestDistance[i] = latestDistance;
                    frontierPriorityQueue.add(new NodeAndWeight(i, latestDistance));
                }
            }
        }
        return shortestDistance;
    }

        这个优先级队列优化了什么呢?

  1. 优化了寻找下一个要到达的点是的逻辑——从顺序查找变成了堆查找;
  2. 没有其他优化了。

3.A-star算法

        在2.1的BFS算法中,如果队列是优先级队列,则遍历就会沿着最优指执行的趋势进行。而这个优先级如果是到起点的距离,则能找到起点到所有节点的最短路径,就变成了迪杰特斯拉算法了。

        如果是一个start点和一个end点呢?找一条这两个节点的通路。

  1. BFS肯定可行;如果队列排序且是距起点的距离,则可以找到最短路径。不过只是起止两点的最短路径。
  2. 权值如果是  f(n) = g(n) + h(n) ,其中 g(n)表示从起点到定点n的路径代价,而h(n)表示节点n到目标节点的估值。

        A-star算法主要用于地图上两个节点的路径。参考文章: Introduction to A* 

        个人感觉:

  1. A-star算法更多的用在坐标系中,而不是图的算法中,而且g(n)和h(n)的计算都比较直观。
  2. 想改变bfs的查找路径方向,可以从‘邻接点’规则和‘f(n)定义两方面下手。很显然,在参考文章中是指对f(n)进行了讨论的。
  3. 推荐文章: Introduction to the A* Algorithm        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值