算法导论22.1图的表示 练习总结 (转载)
转自:http://blog.csdn.net/chan15/article/details/49620221
22.1-1 给定有向图的邻接链表,需要多长时间才能计算出每个结点的出度(发出的边的条数)?多长时间才能计算出每个结点的入度(进入的边的条数)?
ANSWER:① 出度:O(V+E),因为计算 n 个结点的链表长度为 O(n),所以需要计算 O(V) 个链表长度时间为 O(V+E)。② 入度:O(V+E),同理。
22.1-2 给定一棵有 7 个结点的完全二叉树的邻接链表,请给出等价的邻接矩阵表示。这里假设结点的编号为从 1~7。
ANSWER:
22.1-3 有向图 G = (V,E) 的转置是图 G^T = (V,E^T),这里 E^T = {(v,u) ∈ V * V : (u,v) ∈ E}。因此,图 G^T 就是将有向图 G 中所有边的方向反过来而形成的图。对于邻接链表和邻接矩阵两种表示方法,请给出从图G 计算出 G^T 的有效算法,并分析算法的运行时间。
ANSWER:
邻接链表:用 O(V+E) 时间遍历链表,获取所有结点。对结点为 i 的链表,将结点 i 放在以该链表的数组 Adj 为结点的链表中;时间为 O(V+E)。
邻接矩阵:返回原矩阵的转置,时间为 O(V^2)。
22.1-4 给定多图 G = (V,E) 的邻接链表(多图允许重复边和自循环边的图),请给出一个时间为 O(V+E) 的算法,用来计算该图的“等价”无向图 G‘ = (V,E') 的邻接链表表示。这里 E' 是将 E 中的冗余边和自循环边删除后余下的边。删除冗余边指的是将两个节点之间的多条边替换为一条边。
ANSWER:遍历多图 G 的每个链表,并复制链表;若链表的 Adj 元素与链表头节点重复,则不复制该元素;若链表中 Adj 元素重复多次出现,则只复制一次。复制完成后,新的邻接链表若出现只有头结点的链表,则删除该链表。
22.1-5 有向图 G = (V,E) 的平方图是图 G2 = (V,E2),这里,边 (u, v) ∈ E2 当且仅当图 G 包含一条最多由两条边构成的从 u 到 v 的路径。请给出一个有效算法来计算图 G 的平方图 G2。这里图 G 既可以以邻接链表表示,也可以以邻接矩阵表示。请分析算法的运行时间。
ANSWER:邻接矩阵,时间复杂度:O(V^3)。
for i = 1 to n for j = 1 to n if G[i][j] == 1 G2[i][j] = 1 else for k = 1 to n if G[i][k] == 1 and G[k][j] == 1 G2[i][j] = 1 else G2[i][j] = 0
22.1-6 多数以邻接矩阵作为输入的图算法的运行时间为 Ω(V^2),但也有例外。给定图 G 的邻接矩阵表示,请给出一个 O(V) 时间的算法来判断有向图 G 是否存在一个通用汇点。通用汇点指的是入度为 |V| - 1 但出度为 0 的结点。
ANSWER:若结点 i 满足题意,则在邻接矩阵中,第 i 行全为 0,第 i 列全为 1(第 i 行第 i 列除外)。
按结点编号由大到小(从邻接矩阵右下角向左上方向)检测,当检测结点 i 时,若结点 x 与结点 i 的关系满足题意(即 x 指向 i,i 不指向 x),则 x 一定不满足题意。所以,向上检测某结点的同时,也在检测其它结点。执行一次 while 循环后筛选出唯一一个可能成立的 ans 值,再用 O(V) 时间检测其是否成立。
伪代码:
SEARCH_USPOINT(G): i = v j = 1 while i - j > 0 ans = v if G[i][i-j] == 0 and G[i-j][i] == 1 //结点入度加 1,出度为 0 j = j + 1 else //检测下一结点 i = i - j ans = i j = 1 if CHECK(ans) return true else return false CHECK(ans): for i = 1 to V if G[i][ans] != 1 or G[ans][i] != 0 return false else return true
22.1-7 有向无环图 G = (V, E) 的关联矩阵是一个满足下述条件的 |V| * |E| 矩阵 B = (bij):
bij = -1 (如果边 j 从结点 i 发出);1 (如果边 j 进入结点 i);0 (其他)。
请说明矩阵乘积 B*B^T 里的每一个元素代表什么意思。这里 B^T 是矩阵 B 的转置。
ANSWER:
当 i = j 时,B*B^T(i, j) = i 的入度 + i 的出度。
当 i ≠ j 时,B*B^T(i, j) = (i → k → j) 边数 + (i ← k ← j) 边数 - (i ← k → j) 边数 - (i → k ← j)边数;k ∈[1, V]。
22.1-8 假定数组 Adj[u] 的每个记录项不是链表,而是一个散列表,里面包含的是 (u, v) ∈ E 的结点 v。如果每条边被查询的概率相同,则判断一条边是否在图中的期望时间值是多少?这种表示方式的缺陷是什么?请为每条边链表给出一个不同的数据结构来解决这个问题。与散列表相比较,你所给出的新方法存在什么缺陷吗?
ANSWER:
① 搜索期望时间为 O(1),先找到 Adj[u],然后用 O(1) 时间在 u 中找到 v。
② 缺陷:会比邻接链表使用更多空间。
③ 利用二叉搜索树存放每条边链表的值。
④ 新方法缺陷:搜索时间会变成 O(lgn),n 为二叉树大小。