TAOCP 2.3.3 Exercise 15
**Problem restatement.
Section 2.3.3: Other Representations of Trees
Exercise 15. [40] Design an algorithm to compute the product of two polynomials represented as in Fig. 28.
Verified: yes
Solve time: 2m39s
Exercise 2.3.3.15 [40]
Problem restatement. Let two polynomials be represented in the linked-tree sequential form of Fig. 28. That is, each polynomial is a tree in which a node contains fields:
COEFF, the coefficient of the term (possibly zero),EXP, the exponent of the variable corresponding to this node,LCHILD, a pointer to the first child (sub-polynomial for nested variables),RLINK, a pointer to the next sibling node.
Let P and Q denote the roots of the two input polynomials. The goal is to compute the product polynomial
$$ R(x_1, x_2, \dots) = P(x_1, x_2, \dots) \cdot Q(x_1, x_2, \dots) $$
as a tree in the same representation, preserving the invariants of Fig. 28 and combining like terms.
Correct Solution
1. Recursive multiplication of trees
The key observation is that a node in the linked-tree representation may either be a terminal node (no LCHILD) or a nonterminal node (with LCHILD pointing to a sub-polynomial). Multiplication of two nodes must recursively multiply their subtrees.
Define the procedure
$$ \text{MULT}(P, Q) $$
which returns the root of the product polynomial of trees P and Q. The procedure proceeds as follows.
2. Algorithm T [Tree Polynomial Multiplication]
T1. [Base case: empty node.]
If P = null or Q = null, return null.
T2. [Initialize result.]
Set R <- null (empty tree).
T3. [Traverse P.]
For each node Pnode in the top-level list of P (follow RLINK):
- Let
Pcoeff <- COEFF(Pnode)andPexp <- EXP(Pnode). - Let
Pchild <- LCHILD(Pnode).
T4. [Traverse Q.]
For each node Qnode in the top-level list of Q (follow RLINK):
- Let
Qcoeff <- COEFF(Qnode)andQexp <- EXP(Qnode). - Let
Qchild <- LCHILD(Qnode).
T5. [Multiply nodes.]
-
Coefficient: $c \leftarrow Pcoeff \cdot Qcoeff$.
-
Exponent: $e \leftarrow Pexp + Qexp$.
-
Subtree:
-
If
Pchild = nullandQchild = null, setSchild <- null. -
Otherwise, recursively compute
Schild <- MULT(Pchild, Qchild). -
Create a new node
Swith fields:
$$ COEFF(S) = c, \quad EXP(S) = e, \quad LCHILD(S) = Schild, \quad RLINK(S) = null $$
T6. [Insert node into result.]
Insert S into the tree R in canonical order:
- Traverse the top-level nodes of
Rin increasing exponent order. - If a node
Texists withEXP(T) = e:
- If
LCHILD(T) = nullandSchild = null, setCOEFF(T) \leftarrow COEFF(T) + c. - If
LCHILD(T) \neq nullorSchild \neq null, recursively merge the subtrees:
$$
LCHILD(T) \leftarrow \text{ADD_TREES}(LCHILD(T), Schild)
$$
3. Otherwise, insert S at the correct exponent position in R (maintaining order).
T7. [Continue traversal.]
Repeat T4–T6 for all nodes of Q. Repeat T3–T6 for all nodes of P.
T8. [Return result.]
Return R as the root of the product polynomial.
3. Auxiliary procedure: ADD_TREES
The procedure
$$ \text{ADD_TREES}(A, B) $$
merges two trees representing polynomials in canonical form:
- If
A = null, returnB. - If
B = null, returnA. - Compare the
EXPof the rootsAandB:
-
If
EXP(A) < EXP(B), setRLINK(A) <- ADD_TREES(RLINK(A), B)and returnA. -
If
EXP(A) > EXP(B), setRLINK(B) <- ADD_TREES(A, RLINK(B))and returnB. -
If
EXP(A) = EXP(B): -
Sum the coefficients:
COEFF(A) <- COEFF(A) + COEFF(B). -
Recursively merge children:
LCHILD(A) <- ADD_TREES(LCHILD(A), LCHILD(B)). -
Recursively merge siblings:
RLINK(A) <- ADD_TREES(RLINK(A), RLINK(B)). -
Return
A.
This ensures that like terms at all levels are combined and canonical order is preserved.
4. Correctness argument
- Structural correctness:
- Each node
Sis created with its coefficient, exponent, and subtree corresponding to the product ofPnodeandQnode. - The tree
Ris constructed by inserting nodes in exponent order and merging like terms recursively. - Therefore,
Rsatisfies all invariants of the linked-tree representation of Fig. 28.
- Correctness of multiplication:
- Every pair
(Pnode, Qnode)is multiplied exactly once. - For nodes with subtrees, the recursive call
MULT(Pchild, Qchild)correctly computes the product of sub-polynomials. - By induction on the depth of the tree, all coefficients and exponents are computed according to the distributive law for generalized polynomials.
- Combining like terms:
- The
ADD_TREESprocedure ensures that nodes with the same exponent at any level are merged. - Zero coefficients can optionally be removed during insertion if desired, but the algorithm preserves them if required.
- Termination:
- Each traversal of
RLINKand recursive multiplication eventually reachesnullnodes. - Depth of recursion is bounded by the maximum depth of the input trees.
- Therefore, the algorithm terminates.
- Space and time complexity:
- Let
|P|and|Q|denote the number of nodes in the input trees. - In the worst case, the product has up to
|P|*|Q|nodes before merging. - Recursive multiplication and tree insertion may take
O(|P|*|Q|)time for sparse polynomials; merging subtrees incurs additional recursion proportional to subtree sizes.
5. Remarks
- The algorithm is fully recursive and handles nested polynomial structures, unlike the previous flawed solution, which assumed flat monomials.
- By using
ADD_TREES, the algorithm preserves canonical form and merges like terms at all levels. - Zero-coefficient nodes may be retained or pruned according to the application.
- This procedure generalizes naturally to multi-variable polynomials represented as trees with multiple variables corresponding to different levels.
$$ \boxed{R = \text{MULT}(P, Q) \text{ is the root of the product polynomial in linked-tree form}} $$