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)。

posted @ 2020-04-16 16:10  wkfxm  阅读(16568)  评论(0编辑  收藏  举报