Trees
Preorder Traversal
Visit the root before each subtree, producing root-left-right order.
Algorithm
The canonical tree is 4(2(1,3),6(5,7)), so this TypeScript DSA
implementation can be compared directly with the rest of the DSA track.
preorder
Preorder records the current node before visiting left and right subtrees.
Basic Implementation
basic.ts
Replay: real traced execution (multi-file project)
class Node {
value: number;
left: Node | null;
right: Node | null;
constructor(value: number, left: Node | null = null, right: Node | null = null) {
this.value = value;
this.left = left;
this.right = right;
}
}
function render(node: Node | null): string {
if (node === null) return "_";
if (node.left === null && node.right === null) return String(node.value);
return `${node.value}(${render(node.left)},${render(node.right)})`;
}
function sampleTree(): Node {
return new Node(4, new Node(2, new Node(1), new Node(3)), new Node(6, new Node(5), new Node(7)));
}
const root = sampleTree();
const output = [];
function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }
preorder(root);
console.log(`[${output.join(", ")}]`);
tree ← 4(2(1,3),6(5,7)), output ← []
1class Node {2 value: number;values this step4(2(1,3),6(5,7))tree[]outputoutput ← [4]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[] → [4]output4nodeoutput ← [4, 2]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[4] → [4, 2]output2nodeoutput ← [4, 2, 1]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[4, 2] → [4, 2, 1]output1nodeoutput ← [4, 2, 1, 3]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[4, 2, 1] → [4, 2, 1, 3]output3nodeoutput ← [4, 2, 1, 3, 6]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[4, 2, 1, 3] → [4, 2, 1, 3, 6]output6nodeoutput ← [4, 2, 1, 3, 6, 5]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[4, 2, 1, 3, 6] → [4, 2, 1, 3, 6, 5]output5nodeoutput ← [4, 2, 1, 3, 6, 5, 7]
21const output = [];22function preorder(node) { if (node === null) return; output.push(node.value); preorder(node.left); preorder(node.right); }23preorder(root);values this step[4, 2, 1, 3, 6, 5] → [4, 2, 1, 3, 6, 5, 7]output7nodeclass Node
1class Node {2 value: number;values this step[4, 2, 1, 3, 6, 5, 7]output
Complexity
- Time: O(n)
- Space: O(h) recursion stack
Implementation notes
- The sample tree uses the typed
Nodeclass withvalue: numberand nullableleftandrightreferences, then allocates the same4(2(1,3),6(5,7))shape rendered byrender. const output = []is filled byoutput.push(node.value). The checked source relies on inference for the output array and leavespreorder(node)without an explicit parameter annotation.- The recursive function returns immediately on
node === null; otherwise it records the current value, then callspreorder(node.left)andpreorder(node.right). Each non-null child visit appears as another call-stack frame before returning through the null leaf calls. - The trace records visit-before-children states for nodes
4, 2, 1, 3, 6, 5, 7, growing output from[]through[4, 2, 1, 3, 6, 5]to[4, 2, 1, 3, 6, 5, 7]. console.log(\[${output.join(", ")}]`)prints[4, 2, 1, 3, 6, 5, 7]`. Visible allocation is the tree, output array, and joined output string; traversal mutates only the output array, not the node links.