21-2 Depth determination

In the depth-determination problem, we maintain a forest F={Ti}\mathcal F = \{T_i\} of rooted trees under three operations:

MAKE-TREE(v)\text{MAKE-TREE}(v) creates a tree whose only node is vv.

FIND-DEPTH(v)\text{FIND-DEPTH}(v) returns the depth of node vv within its tree.

GRAFT(r,v)\text{GRAFT}(r, v) makes node rr, which is assumed to be the root of a tree, become the child of node vv, which is assumed to be in a different tree than rr but may or may not itself be a root.

a. Suppose that we use a tree representation similar to a disjoint-set forest: v.pv.p is the parent of node vv, except that v.p=vv.p = v if vv is a root. Suppose further that we implement GRAFT(r,v)\text{GRAFT}(r, v) by setting r.p=vr.p = v and FIND-DEPTH(v)\text{FIND-DEPTH}(v) by following the find path up to the root, returning a count of all nodes other than vv encountered. Show that the worst-case running time of a sequence of mm MAKE-TREE\text{MAKE-TREE}, FIND-DEPTH\text{FIND-DEPTH}, and GRAFT\text{GRAFT} operations is Θ(m2)\Theta(m^2).

By using the union-by-rank and path-compression heuristics, we can reduce the worst-case running time. We use the disjoint-set forest S={Si}\mathcal S = \{S_i\}, where each set SiS_i (which is itself a tree) corresponds to a tree TiT_i in the forest F\mathcal F. The tree structure within a set SiS_i, however, does not necessarily correspond to that of TiT_i. In fact, the implementation of SiS_i does not record the exact parent-child relationships but nevertheless allows us to determine any node's depth in TiT_i.

The key idea is to maintain in each node vv a "pseudodistance" v.dv.d, which is defined so that the sum of the pseudodistances along the simple path from vv to the root of its set SiS_i equals the depth of vv in TiT_i. That is, if the simple path from vv to its root in SiS_i is v0,v1,,vkv_0, v_1, \ldots, v_k, where v0=vv_0 = v and vkv_k is SiS_i's root, then the depth of vv in TiT_i is j=0kvj.d\sum_{j = 0}^k v_j.d.

b. Give an implementation of MAKE-TREE\text{MAKE-TREE}.

c. Show how to modify FIND-SET\text{FIND-SET} to implement FIND-DEPTH\text{FIND-DEPTH}. Your implementation should perform path compression, and its running time should be linear in the length of the find path. Make sure that your implementation updates pseudodistances correctly.

d. Show how to implement GRAFT(r,v)\text{GRAFT}(r, v), which combines the sets containing rr and vv, by modifying the UNION\text{UNION} and LINK\text{LINK} procedures. Make sure that your implementation updates pseudodistances correctly. Note that the root of a set SiS_i is not necessarily the root of the corresponding tree TiT_i.

e. Give a tight bound on the worst-case running time of a sequence of mm MAKE-TREE\text{MAKE-TREE}, FIND-DEPTH\text{FIND-DEPTH}, and GRAFT\text{GRAFT} operations, nn of which are MAKE-TREE\text{MAKE-TREE} operations.

a. MAKE-TREE\text{MAKE-TREE} and GRAFT\text{GRAFT} are both constant time operations. FINDDEPTH\text{FINDDEPTH} is linear in the depth of the node. In a sequence of mm operations the maximal depth which can be achieved is m/2m/2, so FIND-DEPTH\text{FIND-DEPTH} takes at most O(m)O(m). Thus, mm operations take at most O(m2)O(m^2). This is achieved as follows: Create m/3m / 3 new trees. Graft them together into a chain using m/3m / 3 calls to GRAFT\text{GRAFT}. Now call FIND-DEPTH\text{FIND-DEPTH} on the deepest node m/3m / 3 times. Each call takes time at least m/3m / 3, so the total runtime is Ω((m/3)2)=Ω(m2)\Omega((m / 3)^2) = \Omega(m^2). Thus the worst-case runtime of the mm operations is Θ(m2)\Theta(m^2).

b. Since the new set will contain only a single node, its depth must be zero and its parent is itself. In this case, the set and its corresponding tree are indistinguishable.

MAKE-TREE(v)
    v = ALLOCATE-NODE()
    v.d = 0
    v.p = v
    return v

c. In addition to returning the set object, modify FIND-SET\text{FIND-SET} to also return the depth of the parent node. Update the pseudodistance of the current node vv to be v.dv.d plus the returned pseudodistance. Since this is done recursively, the running time is unchanged. It is still linear in the length of the find path. To implement FIND-DEPTH\text{FIND-DEPTH}, simply recurse up the tree containing vv, keeping a running total of pseudodistances.

FIND-SET(v)
    if v != v.p
        (v.p, d) = FIND-SET(v.p)
        v.d = v.d + d
        return (v.p, v.d)
    return (v, 0)

d. To implement GRAFT\text{GRAFT} we need to find vv's actual depth and add it to the pseudodistance of the root of the tree SiS_i which contains rr.

GRAFT(r, v)
    (x, d_1) = FIND-SET(r)
    (y, d_2) = FIND-SET(v)
    if x.rank > y.rank
        y.p = x
        x.d = x.d + d_2 + y.d
    else
        x.p = y
        x.d = x.d + d_2
        if x.rank == y.rank
            y.rank = y.rank + 1

e. The three implemented operations have the same asymptotic running time as MAKE\text{MAKE}, FIND\text{FIND}, and UNION\text{UNION} for disjoint sets, so the worst-case runtime of mm such operations, nn of which are MAKE-TREE\text{MAKE-TREE} operations, is O(mα(n))O(m\alpha(n)).