DFS的復雜度分析:
對於鄰接表的存儲方式:因為鄰接表中每條鏈表上的從第2個結點到表尾結點一定是表頭結點的鄰接點,所以遍歷表頭結點的鄰接的過程中只需要遍歷這些頂點即可,無需遍歷其他的頂點,所以遍歷某個頂點的所有鄰接點的復雜度為O(ei),
ei為每個頂點的鄰接點個數,
也就是每條鏈表的邊數。
所以鄰接表版的 dfs 遍歷所有鄰接點的時間復雜度為 O(e1 + e2 + e3 + .... + en) ,因為所有邊數之和為 E , 所以時間復雜度為 O(E) , 又因為訪問每個頂點都必須被訪問一次, 比如設置vis[i] = true, 這個操作一共要執行 V 次,所以,設置所有頂點為已訪問的時間復雜度為O(V), 所以總的時間為查找所有鄰接點的時間加上設置每個頂點為已訪問的時間,總的時間為 O(E) + O(V) = O(E + V)。
鄰接表的 dfs 遞歸的最大深度就是 鏈表條數。最大深度的情況發生在 遍歷第一條鏈表的第一個鄰接結點時,發現它還未被訪問過,所以遞歸訪問它,而遞歸訪問它的第一個鄰接點又發現它還沒被訪問過,又會去遞歸訪問這個鄰接點,這樣,每次遞歸開始查找到的都是未訪問過的結點,每次都會進行向下遞歸,每次遞歸層數都加一,這樣遞歸層數就為鏈表條數。
void dfs(u){ vis[u] = true; for(遍歷頂點u的所有鄰接點,即遍歷u為表頭的那條鏈表){ // 每輪時間復雜度為 O(ei) if(該鄰接點未被訪問){ dfs(v) } } }
鄰接矩陣與鄰接表遍歷過程不同在於,對於鄰接矩陣來說查找某個頂點的所有鄰接點的過程必須遍歷所有頂點,無論是否鄰接都必須判斷一次。所以查找每個頂點的鄰接點的時間復雜度都為O(n), 共有 n 個頂點,這 n 個頂點就表現為遞歸深度最大為 n, 所以總的時間復雜度為 O(n + n + ... + n) = O(n ^2), 而設置每個頂點為已訪問的時間復雜度為O(n), 所以總的時間復雜度為O((n^2 + n), 忽略小階復雜度,保留大階復雜度,所以我們通常說它的時間復雜度為 O(n^2)。
鄰接矩陣版的 dfs 遞歸的最大深度是 頂點個數,情況發生的場景和鄰接表最大深度的情況類似,每次遞歸查找到的第一個鄰接點都是未訪問過的,這樣每次都會
進行向下遞歸,每次遞歸層數都加一,最多遞歸 n 層。
void dfs(u){ vis[u] = true; // 設置 u 頂點為已訪問 for(int v = 0; v < n; v++){ // 每輪的時間復雜度為 O(n) if(vis[v] == false && G[u][v] != inf){ dfs(v) } } }
BFS的復雜度分析
有了上面 DFS 的復雜度分析,BFS 復雜度分析就很簡單了,
BFS是一種借用隊列來存儲的過程,分層查找,優先考慮距離出發點近的點。無論是在鄰接表還是鄰接矩陣中存儲,都需要借助一個輔助隊列,v個頂點均需入隊,最壞的情況下,空間復雜度為O(v)。
鄰接表形式存儲時,每個頂點均需搜索一次,每次結點被入隊一次,出隊一次,所以時間復雜度是 O(V),但是遍歷某個頂點所有鄰接點的復雜度是 O(ei), ei 為第 i 條鏈表的弧的條數,也就是鄰接點個數,所以查找所有鄰接點的復雜度為 O(e1 + e2 + ... + en) = O(E), 加上對每個結點進行入隊出隊的復雜度 O(V), 所以總的時間復雜度為O(E + V).
void bfs(int s){ // s 為選定的遍歷圖的起點 Queue<int> queue; // 定義一個隊列 queue.push(s); while(!queue.empty()){ int top = queue.top(); // 出隊隊首元素 queue.pop(); for(訪問 top 的所有鄰接點){ // 每輪的時間復雜度為 O(ei) if(如果該鄰接點未曾入隊){ 將該結點入隊; } } } }
鄰接矩陣存儲方式時,查找每個頂點的鄰接點所需時間為O(V),即該節點所在的該行的所有列。又因為有n個頂點,
查找所有鄰接點的時間復雜度為O(V^2),
加上對每個結點進行入隊出隊的復雜度 O(V), 所以總的時間復雜度為O(V^2 + V)。省略低階復雜度,最終復雜度為 O(V^2).
void bfs(int s){ // s 為選定的遍歷圖的起點 Queue<int> queue; // 定義一個隊列 queue.push(s); while(!queue.empty()){ int top = queue.top(); // 出隊隊首元素 queue.pop(); for(訪問 top 的所有鄰接點){ // 每輪的時間復雜度為 O(n) if(如果該鄰接點未曾入隊){ 將該結點入隊; } } } }
可以看到 DFS 和 BFS 的遍歷方式,每個版本的時間復雜度是相同的。
這里再附上嚴蔚敏的教材上對 DFS 和 BFS 的復雜度分析:
DFS:
BFS:
