廣度優先搜尋演算法(Breadth-First-Search,BFS)

來源:互聯網
上載者:User

使用電腦求解的問題中,有許多問題是無法用數學公式進行計算推導採用類比方法來找出答案的。這樣的問題往往需要我們根據問題所給定的一些條件,在問題的所有可能解中用某種方式找出問題的解來,這就是所謂的搜尋法或搜尋技術。
通常用搜尋技術解決的問題可以分成兩類:一類問題是給定初始結點,要求找出符合約束條件的目標結點;另一類問題是給出初始結點和目標結點,找出一條從初始結點到達目標結點的路徑。
常見的搜尋演算法有枚舉法、廣度優先搜尋法、深度優先搜尋法、雙向廣度優先搜尋法,A*演算法、回溯法、分支定界法等。這裡來討論一下廣度優先搜尋法。
一.廣度優先搜尋演算法
一般來說,可以採用搜尋演算法解決的這類問題的特點是:
1.有一組具體的狀態,狀態是問題可能出現的每一種情況。全體狀態所構成的狀態空間是有限的,問題規模較小。
2.在問題的解答過程中,可以從一個狀態按照問題給定的條件,轉變為另外的一個或幾個狀態。
3.可以判斷一個狀態的合法性,並且有明確的一個或多個目標狀態。
4.所要解決的問題是:根據給定的初始狀態找出目標狀態,或根據給定的初始狀態和結束狀態,找出一條從初始狀態到結束狀態的路徑。
採用廣度優先搜尋演算法解答問題時,需要構造一個表明狀態特徵和不同狀態之間關係的資料結構,這種資料結構稱為結點。根據問題所給定的條件,從一個結點出
發,可以產生一個或多個新的結點,這個過程通常稱為擴充。結點之間的關係一般可以表示成一棵樹,它被稱為解答樹。搜尋演算法的搜尋過程實際上就是根據初始條
件和擴充規則構造一棵解答樹並尋找符合目標狀態的結點的過程。
廣度優先搜尋演算法中,解答樹上結點的擴充是沿結點深度的“斷層”進行,也就是說,結點的擴充是按它們接近起始結點的程度依次進行的。首先產生第一層結點,
同時檢查目標結點是否在所產生的結點中,如果不在,則將所有的第一層結點逐一擴充,得到第二層結點,並檢查第二層結點是否包含目標結點,...對長度為n
+1的任一結點進行擴充之前,必須先考慮長度為n的結點的每種可能的狀態。因此,對於同一層結點來說,求解問題的價值是相同的,我們可以按任意順序來擴充
它們。這裡採用的原則是先產生的結點先擴充。
廣度優先搜尋演算法中,為了便於進行搜尋,要設定一個表格儲存體所有的結點,為了滿足先產生的結點先擴充的原則,儲存結點的表一般設計成隊列的資料結構。搜尋過
程中不斷地從隊列頭取出結點進行擴充。對產生的新結點,要檢查它是否已在隊列中存在,還要檢查它是否目標結點。如果新結點是目標結點,則搜尋成功,程式結
束;若新結點不是目標結點,並且未曾在隊列中出現過,則將它加入到隊列尾,否則將它丟棄,再從隊列頭取出結點進行擴充......。最終可能產生兩種結
果:找到目標結點,或擴充完所有結點而沒有找到目標結點。
如果目標結點存在於解答樹的有限層上,廣度優先搜尋演算法一定能保證找到一條通向它的最佳路徑,因此廣度優先搜尋演算法特別適用於只需求出最優解的問題。當問題需要給出解的路徑,則要儲存每個結點的來源,也就是它是從哪一個節點擴充來的。
對於不同的問題,用廣度優先搜尋法的演算法基本上都是一樣的。但表示問題狀態的結點資料結構、新結點是否目標結點和是否重複結點的判斷等方面則有所不同,對具體的問題需要進行具體分析。
二.廣度優先搜尋演算法的演算法架構
Private Type TNode                         '定義一個結點資料類型
         ....                                        '根據具體問題確定所需的資料類型
         End Type
Dim State() As TNode                       '定義TNode類型的數組,作為儲存結點的隊列
Private Sub BFS()                            'BFS演算法主程式
   Dim Temp As TNode                       'TNode型臨時結點
   Dim Head As Integer,Tail As Integer '隊列頭指標和尾指標
   ReDim State(0)
   InputData                                           '從檔案中讀入資料進行初始化  
   Head=0
   Tail=0                                                  ' 隊列頭指標和尾指標都指向隊列頭
   Do   While   Head<=Tail                       '隊列非空時迴圈
      '根據具體問題確定一個結點怎樣擴充
Temp= State(0)                                   '取隊列頭的結點
If   Extend Then                               '如果該結點可以擴充則產生一個新結點
If   Not Repeat Then                          '如果新結點未曾在隊列中出現過
    Tail=Tail+1                                      ' 將新結點排入佇列尾
    ReDim Preserve State(Tail)
    State(Tail) =Temp
    State(Tail) .Sire=Head                   '記錄父結點標識
    If Found   Then                               ' 如果新結點是目標結點
   Tail=Tail+1                                  ' 將隊列尾結點的父結點指標指向隊列尾
   ReDim Preserve State(Tail)
   State(Tail) =Tail-1
   PrintPath                                     '輸出路徑
   Exit Sub                                         '退出程式  
    End If
End If
   End If
   Head=Head+1                                  '隊列頭的結點擴充完後出隊,取下一結點擴充
Loop      
End Sub
其中的
InputData是從檔案中讀入初始化的資料,對問題的初始狀態等進行設定的子過程
Extend是判斷結點是否能擴充的子過程,如果能則產生新結點
Repeat是檢查新結點是否在隊列中已經出現的函數,返回一個布爾值
Find則是檢查新結點是否目標結點的函數,也返回一個布爾值
這些過程和函數要根據具體問題進行編寫。另外,PrintPath用遞迴方式輸出路徑的子過程:
Private Sub PrintPath(State() As Node,ByVal   k As Integer)
   If k>0 Then
k=State(k).Sire
PrintPath State,k
OutState State(k)
   End If
End Sub
因為當搜尋到目標結點時,該結點記錄的是其父結點的標識,所以需要再將隊列尾指標前移,將其父結點指向當前的隊尾,也即搜尋到的目標結點。另外得到的路徑
是從隊列尾回到隊列頭的逆向路徑,輸出時要逆轉,所以採用遞迴方式,可以自動輸出正向路徑。子過程OutState與具體的問題有關,要視需要輸出的結點
資訊而定。
這裡將整個求解問題的過程分成了多個子過程,對不同的問題,程式的架構是不變的,只需根據實際情況編寫子過程的代碼即可。  
下面的例子中,雖然某些子過程只有一條語句,為與演算法架構一致,仍使用單獨的子過程表示。轉自:http://hi.baidu.com/cy120032/blog/item/656a3934bfe8123f5bb5f5dc.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.