22.2-8 我们将一棵树T = (V, E)的直径定义为maxδ(u, v)(u,v ∈ V), 也就是说,树中所有最短路径距离的最大值即为
树的直径。请给出一个有效算法来计算树的直径,并分析算法的运行时间。
Answer:
将BFS算法稍作改变
//
T-DIAMETER-BFS(T)
1. s = T.root
2. Q = # //在这儿我们用#代表空集
3. diameter = 0
4. ENQUEUE(Q, s)
5. while Q ≠ #
6. u = DEQUEUE(Q)
7. for each v ∈ Adj[u]
8. v.d = u.d + 1
9. if v.d > diameter
10. diameter = v.d
11. ENQUEUE(Q, v)
12. return diameter;
//
如果将上述的树T以邻接链表的数据结构来存,则我们可以使用BFS算法来计算T的直径。
则T的根结点即为源结点s,对于一个给定源结点s的图G,在BFS终止时会产生一棵以源结点s为根结点的广度优先树.
现在我们证明在给定源结点为T.root的树T在经过BFS形成的广度优先树T'是与原来的树T是相等的。
证明:
因为树T是有向树,故我们在邻接链表中存的边数为|E|,且为有向边。
假设T' ≠ T, 则说明V' ≠ V(肯定有E' ≠ E), 或者E' ≠ E的
当V' ≠ V时,说明以s = T.root为根结点的广度优先搜索树对于原点集有些点是不可达的,
而对于树T来说对于任意一点都存在且唯一的简单路径从T.root到达该结点。故V'≠V不成立
而仅当E' ≠ E,则说明存在一个顶点v它的最短路径不是由他在T中的简单路径组成。则说明该结点
在原图树T中至少存在2条可从T.root到达v的路径。而根据树的定义,结点v不可能存在两条可达路径
故E' ≠ E也是不成立的。
所以对于一个树T,经过BFS后的所形成的广度优先搜索T'是相同的。
2.第二种解决方式是利用DFS算法的思想(邻接链表)
///
T-DIAMETER-DFS(s)
1. if Adj[s] = NIL
2. return 0;
3. diameter = 0
4. for each v ∈ Adj[s]
5. value = T-DIAMETER-DFS(v) + 1
6. if(value > diameter)
7. diameter = value
8. return diameter
3.如果该树用 左孩子-右兄弟(left-child, right-sibling)的数据结构来存储,在存储空间的花费要更少一些。
T-DIAMETER(v)
1. if v = NIL
2. return 0
3. diameter = 0
4. while v ≠ NIL
5. value = T-DIAMETER(v.left-child) + 1
6. if value > diameter
7. diameter = value
8. v = v.right-sibling
9. return diameter
/
以上三种算法前两种都为
O(|E| + |V|) = O(2|V| - 1) = O(|N|)
第三种为
O(|V|)
显然第三种算法不仅在空间存储的花费和时间花费都是要稍微优于前两个算法的。
树的直径。请给出一个有效算法来计算树的直径,并分析算法的运行时间。
Answer:
将BFS算法稍作改变
//
T-DIAMETER-BFS(T)
1. s = T.root
2. Q = # //在这儿我们用#代表空集
3. diameter = 0
4. ENQUEUE(Q, s)
5. while Q ≠ #
6. u = DEQUEUE(Q)
7. for each v ∈ Adj[u]
8. v.d = u.d + 1
9. if v.d > diameter
10. diameter = v.d
11. ENQUEUE(Q, v)
12. return diameter;
//
如果将上述的树T以邻接链表的数据结构来存,则我们可以使用BFS算法来计算T的直径。
则T的根结点即为源结点s,对于一个给定源结点s的图G,在BFS终止时会产生一棵以源结点s为根结点的广度优先树.
现在我们证明在给定源结点为T.root的树T在经过BFS形成的广度优先树T'是与原来的树T是相等的。
证明:
因为树T是有向树,故我们在邻接链表中存的边数为|E|,且为有向边。
假设T' ≠ T, 则说明V' ≠ V(肯定有E' ≠ E), 或者E' ≠ E的
当V' ≠ V时,说明以s = T.root为根结点的广度优先搜索树对于原点集有些点是不可达的,
而对于树T来说对于任意一点都存在且唯一的简单路径从T.root到达该结点。故V'≠V不成立
而仅当E' ≠ E,则说明存在一个顶点v它的最短路径不是由他在T中的简单路径组成。则说明该结点
在原图树T中至少存在2条可从T.root到达v的路径。而根据树的定义,结点v不可能存在两条可达路径
故E' ≠ E也是不成立的。
所以对于一个树T,经过BFS后的所形成的广度优先搜索T'是相同的。
2.第二种解决方式是利用DFS算法的思想(邻接链表)
///
T-DIAMETER-DFS(s)
1. if Adj[s] = NIL
2. return 0;
3. diameter = 0
4. for each v ∈ Adj[s]
5. value = T-DIAMETER-DFS(v) + 1
6. if(value > diameter)
7. diameter = value
8. return diameter
3.如果该树用 左孩子-右兄弟(left-child, right-sibling)的数据结构来存储,在存储空间的花费要更少一些。
T-DIAMETER(v)
1. if v = NIL
2. return 0
3. diameter = 0
4. while v ≠ NIL
5. value = T-DIAMETER(v.left-child) + 1
6. if value > diameter
7. diameter = value
8. v = v.right-sibling
9. return diameter
/
以上三种算法前两种都为
O(|E| + |V|) = O(2|V| - 1) = O(|N|)
第三种为
O(|V|)
显然第三种算法不仅在空间存储的花费和时间花费都是要稍微优于前两个算法的。