算法导论第三版 22.1 图的表示 练习题答案全解析

时间:2022-08-17 00:11:40

 本章主要讲解了图的两种表示方法:邻接链表和邻接矩阵。

课后题:

1.给定有向图的邻接链表,多少时间才能算出每个结点的出度和入度?

 计算出度:

 ①为了计算一个结点的出度,我们需要枚举v结点所有的边,O(出度(v))。

②然后遍历每个结点计算出度,耗费时间为O(|E| + |V|),这里的|V|是必须有的(假设一个图没有边,还是要把所有的点遍历1遍)。

③如果在邻接链表中加入每个结点的边的个数,可以减少到O(|V|)。

计算入度:

计算入度只能遍历整个邻接链表,因此时间复杂度为O(|V)+|E|)。

2.给定一个七个结点的完全二叉树的邻接链表,请写出等价的邻接矩阵表示,这里假设结点的编号为从1~7。

 邻接链表:

1 →2→3

 2→4→5

 3→6→7

 4→2

 5→2

 6→3

 7→3

邻接矩阵 

(0 1 1 0 0 0 0

1 0 0 1 1 0 0

0 0 0 0 0 1 1

0 1 0 0 0 0 0

0 1 0 0 0 0 0

0 0 1 0 0 0 0

0 0 1 0 0 0 0


3. 要求对于邻接矩阵和邻接链表给出从G的算法,并计算其复杂度。

对于邻接矩阵问题十分简单,直接求矩阵的转置即可,意味着把行换成列,把列换成行,对每行操作为O(|V|),需要对|V|行操作,时间复杂度为O|V|^2)。

对于邻接链表,很明显要遍历链表的所有结点来看:如果对于u结点其指向的结点中有v,则在新的链表中,创建一条从v的链表指向u的路径,因此需要遍历所有的链表元素,因此时间复杂度为O|V|+|E|)。

 

3. 给出一个多图(多图为包含重复边和自循环边的图)去除冗余边的复杂度为O(V+E)的算法。

 

遍历邻接链表的所有结点,对于结点u,如果其链表中还有u,则去除所有的u;如果还有重复的v,则去除除了第一个v以外的v结点(这里的标记方法有很多种,可以用个数组)。这样的复杂度应该在O(V+E)

 

4. 求解平方图的问题

算法如下:遍历G的邻接矩阵,对于结点u,如果存在uv的路径,则在G^2的邻接矩阵u中加入v,然后再遍历v结点的链表,如果存在vw,则将w也加入到G^2的邻接矩阵u中。

时间复杂度:这样,再遍历u的时候,如果遍历到了uv这条边,那就在看v的链表,而v的链表里最多有|V|个结点,因此总的复杂度为O|V|+|V|·|E|)。

 

6. 邻接矩阵求通用汇点(入度为|V|-1但是出度为0)的算法

算法如下:从(11)开始扫描邻接矩阵,如果(i,j)是0,则下一个扫描(i,j+1;如果(ij)是1,则下一个扫描(i+1j,i或者j任一方到达|V|时停止。

这样,在最坏的情况下,扫描一行加一列或者一列加一行的结点,一共有2*|V|-1时间复杂度,因此为O(V)

 

7. 关联矩阵,说明BB^T每个元素是什么意思。

其中bij = -1 (如果边j从结点i发出)

1(如果边j进入i结点)

0(其他)

 

此处需要分类讨论:要明白B^Ti行相当于B中第i列。

BB^T对角线上的元素,ii= ,这样如果存在一条由i发出或者进入i的边,都会在ii)中加一(因为就算是-1平方之后也是1),因此ii)就是代表由多少条边从i发出或者进入。

BB^T非对角线元素,ij= ,由公式或者读者自己画矩阵图可以得出,如果k边从i发出从j进入,或者反过来,bik*bjk就等于-1,否则就为0。原因是i,j不可能位于k边的同一侧,所有必然一正一负。如果k不通过i或者不通过j,则其中一个为0,而结果为0。因此i,j)可以表示存在多少i,j之间的边,但是加了一个负号。

 

8. Adj[u]每个项不是链表而是散列表,包含(uv)这条边在图中存在的结点v。判断一条边是否在图中存在的期望时间是多少?

期望的时间是O(1),但是最差情况下要扫描所有结点,因此是O(V)。运用二叉树搜索可以将最坏的时间降低为O(lgV),但是期望时间变坏,因为没有散列表的概率了。