DFS、BFS空间时间复杂度分析
对于一个含有n个节点、e条边的连通无向图,两种遍历方式,分别分析时间空间复杂度。
深度遍历:DFS
它的思想:假设初始状态是图中所有顶点均未被访问,则从某个顶点v出发,首先访问该顶点,然后依次从它的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和v有路径相通的顶点都被访问到。
若此时尚有其他顶点未被访问到,则另选一个未被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。
伪代码描述:
1 void DFSTraverseAL(ALGraph *G) 2 { /*深度优先遍历以邻接表存储的图G*/ 3 int i; 4 for (i = 0; i < G->n; i++) 5 visited[i] = FALSE; /*标志向量初始化*/ 6 for (i = 0; i < G->n; i++) 7 if (!visited[i]) 8 DFSAL(G, i); /*vi 未访问过,从vi 开始DFS 搜索*/ 9 } /*DFSTraveseAL*/ 10 11 void DFSAL(ALGraph *G, int i) 12 { /*以Vi 为出发点对邻接表存储的图G 进行DFS 搜索*/ 13 EdgeNode *p; 14 printf("visit vertex:V%c\n", G->adjlist[i].vertex); /*访问顶点Vi*/ 15 visited[i] = TRUE; /*标记Vi 已访问*/ 16 p = G->adjlist[i].firstedge; /*取Vi 边表的头指针*/ 17 while (p) /*依次搜索Vi 的邻接点Vj,j=p->adjva*/ 18 { 19 if (!visited[p->adjvex]) /*若Vj 尚未访问,则以Vj 为出发点向纵深搜索*/ 20 DFSAL(G, p->adjvex); 21 p = p->next; /*找Vi 的下一个邻接点*/ 22 } 23 } /*DFSAL*/
1)DFS、采用邻接矩阵表示
空间复杂度:
由于DFS需要一个递归工作栈,最差的情况是如图所示。当从第一个节点开始遍历时,先访问它,修改它的访问标记。然后找到它的第一个邻居(把它的邻居称为a),访问a,修改a的访问标记。
从a找到a的邻居(称为b),访问b,修改b的访问标记 ,...,依次递归,每个节点都需要进入函数调用栈,最深的函数栈层数为n,故其空间复杂度为O(n-1)~O(n)。
时间复杂度:
时间复杂度为非两个部分:a:访问每个节点花费的时间 b:在每个节点找邻居花费的时间。
a:n个节点需要O(n);
b:由于是邻接矩阵,对于节点i,需要扫描第i行的每一个元素,需要O(n);
总的复杂度O(n^2)。
2)DFS、采用邻接表表示
空间复杂度:
同邻接矩阵的分析
时间复杂度:
时间复杂度分为两个部分:a:访问每个节点花费的时间 b:在每个节点找邻居花费的时间。
a:n个节点需要O(n);
b:采用邻接表,总共的找邻居时间复杂度就是遍历边表的时间复杂度。对于有向图:O(e),对于无向图O(2e)~O(e)(取最高阶);
总的复杂度O(n+e)。
广度遍历:BFS
伪代码描述:
1 void BFSTraverse(Graph G, Status (*Visit)(int v)) 2 { /*按广度优先非递归遍历图G。使用辅助队列Q 和访问标志数组visited*/ 3 for (v = 0; v < G, vexnum; ++v) 4 visited[v] = FALSE 5 InitQueue(Q); /*置空的队列Q*/ 6 if (!visited[v]) /*v 尚未访问*/ 7 { 8 EnQucue(Q, v); /*v 入队列*/ 9 while (!QueueEmpty(Q)) 10 { 11 DeQueue(Q, u); /*队头元素出队并置为u*/ 12 visited[u] = TRUE; 13 visit(u); /*访问u*/ 14 for (w = FistAdjVex(G, u); w; w = NextAdjVex(G, u, w)) 15 if (!visited[w]) 16 EnQueue(Q, w); /*u 的尚未访问的邻接顶点w 入队列Q*/ 17 } 18 } 19 } /*BFSTraverse*/
它的思想是:从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使得“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问。
直至图中所有已被访问的顶点的邻接点都被访问到。如果此时图中尚有顶点未被访问,则需要另选一个未曾被访问过的顶点作为新的起始点,重复上述过程,直至图中所有顶点都被访问到为止。
1)BFS、采用邻接矩阵表示
空间复杂度:
无论是邻接表还是邻接矩阵,BFS算法需要借助一个辅助队列,在最坏的情况下(如下图从中心节点出发),n个顶点需全入队一次,空间复杂度O(n);
时间复杂度:
时间复杂度为非两个部分:a:访问每个节点花费的时间 b:在每个节点找邻居花费的时间。
a:n个节点需要O(n);
b:由于是邻接矩阵,对于节点i,需要扫描第i行的每一个元素,需要O(n);
总的复杂度O(n^2)。
2)BFS、采用邻接表表示
空间复杂度:
同上
时间复杂度:
时间复杂度分为两个部分:a:访问每个节点花费的时间 b:在每个节点找邻居花费的时间。
a:n个节点需要O(n);
b:采用邻接表,总共的找邻居时间复杂度就是遍历边表的时间复杂度。对于有向图:O(e),对于无向图O(2e)~O(e)(取最高阶);
总的复杂度O(n+e)。