深度优先遍历和广度优先遍历

深度优先遍历的主要思想是:

    首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点:当没有未访问过的顶点时,则回到上一个顶点,继续试探访问别的顶点,直到所有的顶点都被访问过。类似先序遍历。

显然,深度优先遍历是沿着图的某一条分支遍历直到末端,然后回溯,再沿着另一条进行同样的遍历,直到所有的顶点都被访问过为止。
那么,如何存储一个图呢?

常用的方法是使用一个二维数组来存储。 图的邻接矩阵存储法。

二维数组中的第i行第j列表示的就是顶点i到顶点j是否有边。 1 表示有边,自己到自己(即i等于j)设为0.

package BFS_DFS;
import java.util.*;
public class DFS {
    public static int[] book=new int[101];
    public static int sum,n;
    public static int[][] e=new int[101][101];
    public static void dfs(int cur){
        int i;
        System.out.println(cur);
        sum++;//每访问一个顶点,sum就加1
        if(sum==n){
            return;//所有的顶点都已经访问过则直接退出
        }
        for(i=1;i<=n;i++){//从1号顶点到n号顶点依次尝试,看哪些顶点与当前顶点cur有边相连
            //判断当前顶点cur到顶点i是否有边,并判断顶点i是否已访问过
            if(e[cur][i]==1 && book[i]==0){
                book[i]=1;//标记顶点i已经访问过
                dfs(i);//从顶点i再出发继续遍历
            }
        }
        return;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int i,j,m,a,b;
        Scanner sc=new Scanner(System.in);
            n=sc.nextInt();
            m=sc.nextInt();
            for(i=1;i<=n;i++){
                for(j=1;j<=n;j++){
                    if(i==j) e[i][j]=0;
                    else
                        e[i][j]=99999999;//假设99999999为正无穷
                }
            }
            for(i=1;i<=m;i++){
                a=sc.nextInt();
                b=sc.nextInt();
                e[a][b]=1;
                e[b][a]=1;//这里是无向图,需要将e[b][a]=1
            }
            sc.close();
        book[1]=1;//从1号城市出发,标记1号顶点已访问
        dfs(1);
    }

}

广度优先遍历的主要思想是:

首先以一个未被访问过的顶点作为起始顶点,访问其所有相邻的顶点,然后对每个相邻的顶点,再访问它们相邻的未被访问过的顶点,直到所有的顶点都被访问过,遍历结束,类似层次遍历。

过程如下:首先以一个未被访问过的顶点作为起始顶点,比如以1 号顶点作为 起点,将1号顶点放入到队列中,然后将与1 号顶点相邻的未被访问过的顶点 即2 号、3 号和5 号顶点依次再放入到队列中,接下来再将 2 号顶点相邻的未被访问过的顶点4 号放入队列中。遍历结束。

package BFS_DFS;
import java.util.*;
public class BFS {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int i,j,n,m,a,b,cur;
        int[] book=new int[101];
        int[][] e=new int[101][101];
        int[] que=new int[10001];
        int head,tail;
        LinkedList<Integer> queue=new LinkedList<>();
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(i==j)e[i][j]=0;
                else e[i][j]=99999999;

            }
        }
        for(i=1;i<=m;i++){
            a=sc.nextInt();
            b=sc.nextInt();
            e[a][b]=1;
            e[b][a]=1;//无向图,
        }
        sc.close();
        //队列初始化
        head=1;
        tail=1;
        que[tail]=1;
        tail++;
        book[1]=1;//标记1 号顶点已访问

        //当队列不为空的时候循环
        while(head<tail){
            cur=que[head];//当前正在访问 的顶点编号
            for(i=1;i<=n;i++){
                //判断从顶点cur到顶点i是否有边,并判断顶点i是否已经访问过
                if(e[cur][i]==1 && book[i]==0){
                    //如果顶点cur 到顶点i有边,且顶点i没有访问过,则将顶点i入队列
                    que[tail]=i;
                    tail++;
                    book[i]=1;
                }
                //如果tail大于n,则表明所有顶点都已经被访问过
                if(tail>n)
                    break;
            }
            //注意:不要忘记当一个顶点扩展结束后, head++,然后才能继续向下扩展
            head++;

        }
        for(i=1;i<tail;i++){
            System.out.println( que[i]);
        }
    }

}

eg: 求出 1 号城市 到 5 号城市的最短路径。
可以用一个二维矩阵来存储任意两个城市之间的路程。比如
e[1][2]的值为2表示从1 号城市到2 号城市的路程为2 公里。

package BFS_DFS;
import java.util.*;
public class DFS_1 {
    static int min=99999999;
    static int[] book=new int[101];
    static int[][] e=new int[101][101];
    static int n;
    //cur 表示当前所在城市的编号,dis 是当前已经走过的路程
    public static void dfs(int cur, int dis){
        int j;
        //如果当前走过的路程已经大于之前找到的最短路,则没有必要再往下尝试了,立即返回
        if(dis>min)return;
        if(cur==n){//判断是否到达了目标城市
            if(dis<min)min=dis;//更新最小值
            return;
        }
        for(j=1;j<=n;j++){//从1 号城市到 n号城市依次尝试
            //判断当前城市cur到城市j是否有路,并判断城市j是否在已经走过的路径中
            if(e[cur][j] != 99999999 && book[j] ==0){
                book[j]=1;//标记城市j已经在路径中
                dfs(j,dis+e[cur][j]);//从城市j出发,继续寻找目标城市
                book[j]=0;//之前一步探索完毕之后,取消对城市j的标记
            }
        }
        return;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int i,j,m,a,b,c;
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(i==j)e[i][j]=0;
                else
                    e[i][j]=99999999;
            }
        }
        for(i=1;i<=m;i++){
            a=sc.nextInt();
            b=sc.nextInt();
            c=sc.nextInt();
            e[a][b]=c;//有向图
        }
        book[1]=1;//从1 号城市出发,标记1 号城市已经在路径中
        dfs(1,0);//1 表示当前城市所在的城市编号,0 表示当前已经走过的路程
        System.out.println(min);
    }

}

图就是有 N个顶点和 M条边组成的集合。
广度优先搜索更加适用于所有边的权值相同的情况。
eg: 最少转机次数
还是使用邻接矩阵来存储图。

package BFS_DFS;
import java.util.*;
class Note{
    int x;//城市编号
    int s;//转机次数
    Note(int x, int s){
        this.x=x;
        this.s=s;
    }
}
public class BFS_1 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Note[] que=new Note[2501];
        int[][] e=new int[51][51];
        int[] book=new int[51];
        int head,tail;
        int i,j,n,m,a,b,cur,start,end,flag=0;   
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        start=sc.nextInt();
        end=sc.nextInt();
        //初始化二维矩阵
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(i==j)e[i][j]=0;
                else
                    e[i][j]=99999999;
            }
        }
        //读入城市之间的航班
        for(i=1;i<=m;i++){
            a=sc.nextInt();
            b=sc.nextInt();
            e[a][b]=1;
            e[b][a]=1;//无向图
        }
        //队列初始化
        head=1;
        tail=1;
        //从start号城市出发,将start号城市加入队列
        que[tail].x=start;
        que[tail].s=0;
        tail++;
        book[start]=1;//标记start号城市已在队列中
        //当队列不为空时循环
        while(head<tail){
            cur=que[head].x;//当前队列中首城市的编号
            for(j=1;j<=n;j++){
                if(e[cur][j]!=99999999&& book[j]==0){
                    que[tail].x=j;
                    que[tail].s=que[head].s+1;//转机次数加1
                    tail++;
                    book[j]=1;
                }
                //如果到达目标城市,退出循环
                if(que[tail-1].x==end){
                    flag=1;
                    break;
                }
            }
            if(flag==1)
                break;
            head++;//注意: 不要忘记当一个点扩展结束后,head++才能继续扩展
        }
        System.out.println(que[tail-1].s);//最少转机次数
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值