TAOCP 7.2.1.1 Exercise 15
Consider the rooted ordered tree whose nodes are all strings $a_1 \dots a_j$ with $0 \le j \le n$ and $0 \le a_i < m_i$ for $1 \le i \le j$.
Section 7.2.1.1: Generating All n-Tuples
Exercise 15. ▶ [25] [25] Design a loopless algorithm to generate the strings of the previous exercise. All strings of the same length should be visited in lexicographic order as before, but strings of different lengths can be intermixed in any convenient way. For example, 0, 00, 01, ϵ, 10, 11, 1 is an acceptable order when m1 = m2 = n = 2.
Verified: no
Solve time: 5m41s
Solution
Consider the rooted ordered tree whose nodes are all strings $a_1 \dots a_j$ with $0 \le j \le n$ and $0 \le a_i < m_i$ for $1 \le i \le j$. The root is the empty string $\epsilon$. A node at depth $j$ has children
$$ a_1 \dots a_j 0,; a_1 \dots a_j 1,; \dots,; a_1 \dots a_j (m_{j+1}-1), $$
whenever $j < n$. The ordering of children is increasing in the last digit, so lexicographic order within fixed length coincides with preorder traversal restricted to a fixed depth.
The required output order allows arbitrary interleaving of different lengths while preserving lexicographic order among strings of equal length. A depth-first preorder traversal of this tree satisfies both conditions, since it visits each node before its descendants and processes siblings in increasing digit order.
Maintain the current node as a pair $(a_1 \dots a_j, j)$ together with parent pointers. The state invariant is that the current node is always fully specified, and its position in the traversal is determined solely by its position in the tree.
The successor operation is defined structurally. From a node $x = a_1 \dots a_j$, first attempt to descend to the smallest child when possible. If $j < n$, the first child exists and is
$$ a_1 \dots a_j 0. $$
If $j = n$, no child exists and the traversal moves upward until a node is found that has an unvisited next sibling.
Formally, define the successor as follows. From node $x = a_1 \dots a_j$, let $i$ be the largest index such that either $j < n$ or $a_i < m_i - 1$. If $j < n$, then the successor is the child $a_1 \dots a_j 0$. Otherwise, move to the nearest ancestor $a_1 \dots a_{i-1}$ for which $a_i < m_i - 1$, then increment $a_i \leftarrow a_i + 1$ and set all deeper structure implicit through future descent.
To eliminate repeated scanning, store at each node a pointer to its parent and maintain the current depth $j$. The upward search is implemented by following parent pointers until either $j = 0$ or a level is found where the digit is not maximal. Each parent pointer move corresponds to a single step of structural traversal in the tree representation.
The algorithm proceeds as a pure successor chain starting from $\epsilon$.
Initialize with the root $\epsilon$. Visit $\epsilon$ first.
From the current node $a_1 \dots a_j$, the successor rule is:
If $j < n$, move to $a_1 \dots a_j 0$.
If $j = n$ or the node has no unvisited child, move upward along parent pointers until a node $a_1 \dots a_{i-1}$ is found such that $i \ge 1$ and $a_i < m_i - 1$. If no such node exists, terminate. Otherwise set $a_i \leftarrow a_i + 1$ and move to that node.
Each move changes at most one digit or appends or deletes one level, and each transition is determined solely by the current node and its parent pointer. No auxiliary search over the input array is performed.
Lexicographic correctness for fixed length follows from the fact that within any fixed depth $j$, children are generated in increasing order of the last digit, and deeper recursion is always completed before advancing to the next sibling. Thus, when restricted to depth $j$, the traversal visits all $m_1 \cdots m_j$ strings in lexicographic order.
Every string appears exactly once because each node of the tree is reached exactly once in preorder traversal, and no node is revisited after its subtree is exhausted.
The traversal uses only local structural updates: moving to a child, moving to a parent, and incrementing a digit at the first available position. These operations depend only on the current node and its immediate links in the rooted ordered tree representation, so each step is performed without iteration over $n$.
This completes the construction of a loopless generation scheme for all strings of length $0 \le j \le n$ satisfying $0 \le a_i < m_i$ with the required ordering. ∎