什麼是 DFS
DFS 是深度優先遍歷,將序列抽象成樹狀結構,以優先深度的方式進行遍歷,獲取想要的結果
例如
假設一個樹的結構如下:
1
2 3
4 5 5 7
使用深度優先遍歷的遍歷順序就是1->2->4->5->3->5->7
,也就是說,深度優先遍歷會從根節點root
開始,以深度優先遍歷到其一個 不能再繼續向下遍歷 的子孫節點,然後回溯到該節點的父節點,再重複向下遍歷和回溯的過程
優缺點
DFS 的優點是,使用 DFS 進行遍歷,空間的佔用是O(h)
(h 爲樹的高度)級別的,因爲空間佔有最多的時候,也就是遍歷到最深的葉子節點時,此時空間的使用是等於樹的高度的
而由於 DFS 執着與向下搜索,可能會錯過更近的答案,從而浪費運算的時間,即如果樹的第二層和第五層都存在答案,DFS 可能會先找到第五層的目標而不是第二層的
例子
這是一道全排列問題,即給定n
,我們要給出1 ~ n
這些數字所能排列出的所有情況,這裏1 ≤ n ≤ 7
思考
首先考慮思路,全排列問題是經典的 DFS 問題,假定n = 3
,我們要給出1 ~ 3
的全排列,正確結果如下:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
我們可以把它抽象爲一個樹,我們首先考慮第一位的元素,有三種情況1、2、3
,這就是樹的三個分支,再考慮1
的分支的第二位,有12、13
兩種情況,這兩種情況又是1
的兩個分支,在考慮12
,只剩123
一種情況了,到此,從1
開始的一個分支就徹底結束了,我們也得到了全排列的第一個情況
這是我們還位於123
,下一步就是回溯,向上回溯,首先來到12
,我們發現它只有123
一個分支,已經被遍歷完了,所以繼續向上回溯,來到1
,我們發現它還有一個13
分支沒有遍歷,我們就繼續遍歷13
,如此一直重複下去,直到所有的分支都遍歷結束後,我們也就得到了全排列的全部結果
代碼 + 註釋
#include<iostream>
using namespace std;
const int N = 10;
int n;
// 用來存儲結果的數組
int path[N];
// 用來標誌元素是否被使用過的數組
bool st[N];
void dfs(int u) {
// 如果 dfs 層數 == 最大深度,就輸出這種情況
if (u == n) {
for (int i = 0; i < n; i++)
printf("%d ", path[i]);
return;
}
// 深度優先遍歷
for (int i = 1; i <= n; i++) {
// 每遍歷到一個元素,先檢測是否重複
if (!st[i]) {
// 設定當前位置的值
path[u] = i;
// 將這個值標記爲已用
st[i] = true;
// 繼續向下遍歷
dfs(u + 1);
// 恢復原樣
st[i] = false;
}
}
}
int main() {
cin >> n;
// 從 0 開始 DFS
dfs(0);
}