树的直径问题

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|)
显然第三种算法不仅在空间存储的花费和时间花费都是要稍微优于前两个算法的。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最小生成直径可以通过 Kruskal 算法得到最小生成,然后利用 DFS 或 BFS 算法遍历该得到最长路径的长度即为直径。下面是一个基于 Matlab 的实现示例: ```matlab function diameter = MST_Diameter(adj_matrix) % adj_matrix: 邻接矩阵 % diameter: 最小生成直径 n = size(adj_matrix, 1); edges = []; for i = 1:n-1 for j = i+1:n if adj_matrix(i,j) > 0 edges = [edges; i,j,adj_matrix(i,j)]; end end end edges = sortrows(edges, 3); % 按边权值排序 % Kruskal算法求最小生成 parent = 1:n; rank = zeros(n, 1); mst = []; for i = 1:size(edges, 1) u = edges(i,1); v = edges(i,2); w = edges(i,3); pu = find(parent, u); pv = find(parent, v); if pu ~= pv mst = [mst; u,v,w]; if rank(pu) < rank(pv) parent(pu) = pv; elseif rank(pu) > rank(pv) parent(pv) = pu; else parent(pv) = pu; rank(pu) = rank(pu) + 1; end end end % DFS遍历最小生成 visited = zeros(n, 1); stack = [1, 0]; % 栈中存储节点和对应的深度 depth = 0; while ~isempty(stack) node = stack(end, 1); depth = stack(end, 2); stack(end, :) = []; visited(node) = 1; for i = 1:size(mst, 1) if mst(i,1) == node && ~visited(mst(i,2)) stack = [stack; mst(i,2), depth+1]; elseif mst(i,2) == node && ~visited(mst(i,1)) stack = [stack; mst(i,1), depth+1]; end end end diameter = depth; ``` 该实现首先将邻接矩阵中的边按权值排序,然后通过 Kruskal 算法得到最小生成。接着利用 DFS 遍历该最小生成,从根节点开始计算深度,最终得到最长路径的长度,即为最小生成直径

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值