【人工智能】Java实现宽度优先搜索(Breadth-First Search,BFS)任意两点之间的所有路径

1.原理

宽度优先搜索(Breadth-First Search)类似于层次搜索,搜索深度逐渐加深。

【人工智能】Java实现宽度优先搜索(Breadth-First Search,BFS)任意两点之间的所有路径_第1张图片

如上图所示,如果要搜索1=>6的路径,会经过下面的顺序

1

12,18

123,126(找到),186(找到),187

1234,1235,1876(找到)

12345,12356(找到)

123456(找到)

2.Java编码

1)数据结构

A 一个顶点的邻接点的表示

如上图中的顶点6可以表示为:6,{2,5,7,8}

如果加上边的权重可以表示为:6,{2,5,7,8},{3,3,1,2}

import java.util.Arrays;
import java.util.List;

public class Adjacent {
    int vertex; //顶点
    List child; //顶点的所有邻接顶点
    List weight; //上面边对应的权重
    public  Adjacent(int v,Integer[] c,Integer[] w)
    {
        vertex=v;
        child= Arrays.asList(c);
        weight=Arrays.asList(w);
    }
}

B 图的表示

顶点集合,如上图{1,2,3,4,5,6,7,8}

所有边集合,如上图可表示为:

1,{2,8}

2,{1,3,6}

3,{2,4,5}

......

8,{1,6,7}

当然,这样表示对于无向图有冗余的,但对有向图的表示还是可以。

public class Graph {
    List vertexes=new ArrayList<>(); //顶点集合
    List  edge=new ArrayList<>(); //所有邻接边的集合
    public  Graph(){}
    public  Graph(String[] v,Adjacent[] adj)
    {
        vertexes= Arrays.asList(v);
        edge=Arrays.asList(adj);
    }
}

2).简单输出图

  public void print()
    {
        for(int i=0;i

3)查找顶点的编号

   public int searchVertex(String v)
    {
        for(int i=0;i

4)判断路径字符串数组是否存在某个结点

    public  boolean  isInStringArray(String[] s,int v)
    {
        for(int i=0;i

5)宽度优先搜索代码

思路:frontier表示路径队列,采用字符串表示路径,如路径012,表示到达顶点2需经过编号为0,1的顶点。explored表示已探索的顶点集合,在该集合中的顶点不再扩展。而allPath表示找到的所有路径的集合。代码中的while循环负责遍历所有顶点,而其中的for循环找到当前遍历的顶点的所有邻接顶点,如果找到的顶点不在explored集合中或者不在当前路径中,分两种情况讨论:一是找到的顶点正好是目标顶点,则将当前路径与该顶点组合成新路径并添加到allPath(表示找到的路径)集合中;二是如果找到的顶点不在当前路径上,则将当前路径连同找到的这个结点组合成新路径将其加入到frontier 队列中。

public ArrayList  bfs(int src,int dst)
    {
        if(src<0 || dst<0 || src>=vertexes.size()
             || dst>=vertexes.size()) return null;
        //路径队列
        Queue frontier=new LinkedList<>();
        //已探索顶点集合
        ArrayList  explored=new ArrayList<>();
        //所有路径集合
        ArrayList allPath=new ArrayList<>();
        frontier.offer(String.valueOf(src));
        while(!frontier.isEmpty())
        {   //将队首路径出队
            String  p=frontier.remove();
            String[] pathSplit=p.split("-");
            //获取路径的最后一个结点
            int ver=Integer.parseInt(pathSplit[pathSplit.length-1]);
            //表示已探索过该结点
            explored.add(ver);
            for(int i=0;i

6)按顶点解析输出路径

   public  void  parsePath(ArrayList path)
    {
        for(int i=0;i"+vertexes[Integer.parseInt(realPath[j])]);
            }
            System.out.println();
        }
    }

3.测试编码

import java.util.*;

public class Main {

    public static void main(String[] args) {
        //顶点集合
        String[] city={"c1","c2","c3","c4","c5","c6","c7","c8"};
        //每个顶点的邻接顶点集合
        Adjacent[] adj=new Adjacent[8];
        Integer[][] a={{1,7},{0,2,5},{1,3,4},{2,4},{2,3,5},{1,4,6,7},{5,7},{0,5,6}};
        Integer[][] b={{5,2},{5,2,3},{2,4,5},{4,2},{5,2,3},{3,3,1,2},{1,3},{2,2,3}};
        for(int i=0;i

输出结果为:

c4=>c5=>c6
c4=>c3=>c2=>c6
c4=>c3=>c5=>c6
c4=>c5=>c3=>c2=>c6
c4=>c3=>c2=>c1=>c8=>c6
c4=>c3=>c2=>c1=>c8=>c7=>c6
c4=>c5=>c3=>c2=>c1=>c8=>c6
c4=>c5=>c3=>c2=>c1=>c8=>c7=>c6

可以看到,找到的路径按路径顶点个数排序,这因为是宽度优先搜索,从源结点一层一层去搜索目标结点。

4.分析

BFS时间复杂度和空间复杂度皆为:O(b^d), b表示每一层的结点为b个,d表示总的搜索深度。当b=10,d=16时,这个数据将非常大,空间复杂度将达到10EB级别。BFS算法在每一步扩展时,若行动代价是一样的,则是最优的,如本例中并没有考虑权值,而只是简单考虑其深度;否则就不是最优的,这可以使用一致代价搜索算法(Uniform-Cost Search,UCS)使得每步都是最优的。BFS使用一般队列即可,而UCS使用优先级队列来处理后续结点。

5.计算路径权重

路径权重的计算比较简单,在此略过

6.DFS及其他

DFS(Deep-First Search)总是沿着当前结点往最深处探索,很快会推进到其最深层。编程时,一般使用栈(Stack,先进后出,LIFO)来存储后继邻接顶点。显然DFS不是最优的。请看DFS的输出结果:

c4=>c5=>c6

c4=>c5=>c3=>c2=>c6

c4=>c5=>c3=>c2=>c1=>c8=>c6

c4=>c5=>c3=>c2=>c1=>c8=>c7=>c6

c4=>c3=>c5=>c6

c4=>c3=>c2=>c6

c4=>c3=>c2=>c1=>c8=>c6

c4=>c3=>c2=>c1=>c8=>c7=>c6

显然DFS的输出有些乱,但也是有规律的,就是一个方向的路径输出完后,再输出其他路径,这是因为DFS使用栈的原因,DFS总是先朝一个方向不断前进、搜索。

DFS的时间复杂度为:O(b^d),这与BFS差不多,但其空间复杂度降低到O(bd),这在空间复杂度上是非常有优势的。DFS的改进算法:深度受限搜索DLS——根据情况限制搜索深度,迭代加深的深度优先搜索IDS——不断增加深度限制,直到找到目标。还有一种称为叫迭代加长搜索ILS,按路径代价不断叠加受限。双向搜索是从两个方向进行搜索,一个从开始点搜索,另一个从目标点搜索,若两者相遇,则找到解,显然双向搜索不是最优解,但其时间、空间复杂度大大降低:O(b^(d/2))。但存在结点的Predecessors(一个结点的双亲集)定义问题,这个定义其实也不难。

你可能感兴趣的:(【人工智能】Java实现宽度优先搜索(Breadth-First Search,BFS)任意两点之间的所有路径)