1. 程式人生 > >遞迴與回溯,DFS及BFS的演算法

遞迴與回溯,DFS及BFS的演算法

遞迴:就是出現這種情況的程式碼: (或者說是用到了棧)

解答樹角度:在dfs遍歷一棵解答樹

優點:結構簡潔

缺點:效率低,可能棧溢位

遞迴的一般結構:

void f()  
{  
     if(符合邊界條件)  
    {  
       ///////  
        return;  
    }  

     //某種形式的呼叫  
     f();  
} 

回溯:遞迴的一種,或者說是通過遞迴這種程式碼結構來實現回溯這個目的。回溯法可以被認為是一個有過剪枝的DFS過程。

解答樹角度:帶回溯的dfs遍歷一棵解答樹

回溯的一般結構:

void dfs(int
當前狀態) { if(當前狀態為邊界狀態) { 記錄或輸出 return; } for(i=0;i<n;i++) //橫向遍歷解答樹所有子節點 { //擴展出一個子狀態。 修改了全域性變數 if(子狀態滿足約束條件) { dfs(子狀態) } 恢復全域性變數//回溯部分
} }

經典例題,比如解數獨問題。

BFS與 DFS

BFS的佔用的是佇列的空間,DFS 佔用的是棧的空間(因為遞迴)。BFS和DFS的空間複雜度恰好相反。對鏈狀圖,BFS最好(佇列中最多隻有1個元素),DFS最差(所有節點都在根節點的遞迴內)。對起點與其他所有點相鄰的圖,DFS最好(遞迴深度為1),BFS最差(佇列中放滿了所有與起點相鄰的圖)。
BFS一般結構:

queue<type> q;

q.push(初始狀態);



 while (!q.empty())

{

  type t = q.front() ;

  q.pop();

  遍歷 t 的各個Next狀態  next

  { 

    if
(next is legal)       q.push(next); 計數或維護等;   } }

但是BFS的狀態數一多,需要的空間就會較大。
DFS 一般結構與回溯相似

DFS(頂點) 

{

  處理當前頂點,記錄為已訪問

  遍歷與當前頂點相鄰的所有未訪問頂點

  {

      標記更改;

      DFS( 下一子狀態);

      恢復更改;

  }

}