深度優先遍歷和廣度優先遍歷

深度優先遍歷的主要思想是:

    首先以一個未被訪問過的頂點作爲起始頂點,沿當前頂點的邊走到未訪問過的頂點:當沒有未訪問過的頂點時,則回到上一個頂點,繼續試探訪問別的頂點,直到所有的頂點都被訪問過。類似先序遍歷。

顯然,深度優先遍歷是沿着圖的某一條分支遍歷直到末端,然後回溯,再沿着另一條進行同樣的遍歷,直到所有的頂點都被訪問過爲止。
那麼,如何存儲一個圖呢?

常用的方法是使用一個二維數組來存儲。 圖的鄰接矩陣存儲法。

二維數組中的第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);//最少轉機次數
    }

}
發佈了83 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章