無向圖(三)

** 廣度優(yōu)先搜索 **

單點路徑問題。給定一幅圖和一個起點s,回答從s到給定目的地頂點v是否存在一條路徑?如果有找出其中最短的那一條。

解決這個問題的經典方法是廣度優(yōu)先搜索。要找到從s到v的最短路徑,從s開始,在所有由一條邊就可以達到的頂點中尋找v,如果找不到就繼續(xù)從所有兩條邊可以到達的頂點中尋找v,如此一直繼續(xù)下去。

public class BreadthFirstPaths{
    private boolean[] marked;       //判斷到達該頂點的最短路徑是否已知
    private int[] edgeTo;         //到達該頂點的已知路徑上的最后一個頂點
    private final int s;            // 起點
    
    public BreadthFirstPaths(Graph G, int s){
        marked = new boolean[G.V()];
        edgeTo = new int[G.V()];
        this.s = s;
        bfs(G,s);
    }
    private void bfs(Graph G, int s){
        Queue<Integer> queue = new Queue<Integer>();
        marked[s] = true;            //標記起點
        queue.enqueue(s);          //將它加入隊列
        while(!queue.isEmpty()){
            int v = queue.dequeue();            //從隊列中刪去下一個頂點
            for( int w : G.adj(v)){
                edgeTo[w] = v;           //保存最短路徑的最后一條邊
                marked[w] = true;      //標記它,因為最短路徑已知
                queue.enqueue(w);    //將它添加到隊列中
            }
        }
    }
    public boolean hasPathTo(int v){
        return marked[v];
    }
    public Iterable<integer> pathTo(int v)
    //和深度優(yōu)先算法相同。
}

深度優(yōu)先搜索的一些應用
深度優(yōu)先搜索可以用于找出一幅圖所有的連通分量。定義如下API:

public class CC
             CC(Graph G)    //預處理構造函數
     boolean connected(int v, int w)         //判斷v和w是否連通
         int count()          //連通分量數
         int id(int v)          //v所處在的連通分量的標識符(0 ~ count()-1)

CC的實現使用了marked數組來尋找一個頂點來作為每個連通分量中深度優(yōu)先搜索的起點。此外,它還使用了一個以頂點為索引的數組id,將同一連通分量的標識符關聯起來。

public class CC{
    public static void main(String[] args){
        Graph G = new Graph(new In(args[0]));
        CC cc = new CC(G);
        int M = cc.count();
        StdOut.println(M + " components");
        Bag<Integer>[]  components;
        components = (Bag<Integer>[]) new Bag[M];
        for( int i=0; i<M; i++)
            components[i] = new Bag<Integer>();
        for( int v = 0; v<G.V(); v++)
            components[cc.id(v)].add(v);
        for( int i=0; i<M; i++){
            for(int v:components[i])
                StdOut.print(v + " ");
            StdOut.println();
        }
    }

    public boolean[] marked;
    private int[] id;
    private int count;
    public CC(Graph G){
        marked = new boolean[G.V()];
        id = new int[G.V()];
        for( int s=0; s<G.V(); s++)
            if(!marked[s]){
                dfs(G,s);
                count++;
            }
    }
    private void dfs(Graph G, int v){
        marked[v] = true;
        id[v] = count;
        for( int w:G.adj(v))
            if(!marked[w])
                dfs(G, w);
    }
    public boolean connected(int v, int w){
        return id[v] == id[w];
    }
    public int id(int v){
        return id[v];
    }
    public int count(){
        return count;
    }
}

CC中基于深度優(yōu)先搜索解決的圖連通性問題的方法與之前的union-find算法相比,雖然理論上更快(能保證所需的時間是常數,而union-find算法不行),但在實際應用中,union-find算法更快,因為它不需要完整的構造并表示一幅圖。且union-find算法是一種動態(tài)算法,而深度優(yōu)先算法必須對圖進行預處理。
深度優(yōu)先算法的遞歸實現能夠讓我們進行復雜的運算并為一些圖的處理問題給出簡潔的解決方案。

  • G是否為無環(huán)圖(不考慮自環(huán)和平行邊)
    public class Cycle{
    private boolean[] marked;
    private boolean hasCycle;
    public Cycle(Graph G){
    marked = new boolean[G.V()];
    for( int s = 0; s < G.V(); s++)
    if(! marked[s])
    dfs(G, s, s);
    }
    private void dfs(Graph G, int v, int u){
    marked[v] = true;
    for( int w: G.adj(v))
    if(!marked[w])
    dfs(G, w, v);
    else if( w != u) hasCycle = true;
    }
    public boolean hasCycle(){
    return hasCycle;
    }
  • G是否為二分圖

二分圖是一種能夠將所有結點分為兩部分的圖,其中圖的每一條邊所連接的兩個頂點都分別屬于不同的部分。

  public class TwoColor{
      private boolean[] marked;
      private boolean[] color;
      private boolean isTwoColorable = true;
      public TwoColor(Graph G){
          marked = new boolean[G.V()];
          color = new boolean[G.V()];
          for( int s = 0; s<G.V(); s++)
              if( ! marked[s])
                  dfs(G,w);
      }
      private void dfs(Graph G, int v){
          marked[v] = true;
          for( int w: G.adj(v))
              if(!marked[w]){
                  color[w] = !color[v];
                  dfs(G, w);
              }
              else if(color[w] == color[v]) isTwoColorable = false;
      }
      public boolean isBipartite(){
          return isTwoColorable;
      }
  }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,922評論 0 33
  • 為了更方便的討論圖處理的算法,我們先設計將圖的表現和實現分開。為每個任務創(chuàng)建一個類,用例創(chuàng)建相應的對象來完成任務。...
    sleepyjoker閱讀 233評論 0 0
  • 數據結構與算法--拓補排序及無環(huán)加權有向圖的最短路徑 現實生活中一些項目工程、生產開發(fā),都有一個所謂的流程。一個流...
    sunhaiyu閱讀 2,448評論 0 8
  • /*若以二維數組存儲圖信息, 負責度比定為n^2, 采用鏈表存儲*/ 基礎存儲類型為Item(用來存儲基本類型),...
    awesomefighter閱讀 542評論 0 0
  • 作者:大地行者 本文寫于2012年12月18日 前段時間,跟老板一起去了浉河港那邊,干什么?去看望留守兒童,捐點錢...
    大地_行者閱讀 443評論 0 0

友情鏈接更多精彩內容