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 Ruby 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.rb
Replay: real traced execution (multi-file project)
class Node
  attr_accessor :value, :left, :right
  def initialize(value, left = nil, right = nil)
    @value = value
    @left = left
    @right = right
  end
end
def render(node)
  return "_" if node.nil?
  return node.value.to_s if node.left.nil? && node.right.nil?
  "#{node.value}(#{render(node.left)},#{render(node.right)})"
end
def sample_tree
  Node.new(4, Node.new(2, Node.new(1), Node.new(3)), Node.new(6, Node.new(5), Node.new(7)))
end
def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end
output = []
preorder(sample_tree, output)
puts "[#{output.join(', ')}]"
  1. tree ← 4(2(1,3),6(5,7)), output ← []

    1class Node2  attr_accessor :value, :left, :right
    values this step4(2(1,3),6(5,7))tree[]output
  2. output ← [4]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[] [4]output4node
  3. output ← [4, 2]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[4] [4, 2]output2node
  4. output ← [4, 2, 1]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[4, 2] [4, 2, 1]output1node
  5. output ← [4, 2, 1, 3]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[4, 2, 1] [4, 2, 1, 3]output3node
  6. output ← [4, 2, 1, 3, 6]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[4, 2, 1, 3] [4, 2, 1, 3, 6]output6node
  7. output ← [4, 2, 1, 3, 6, 5]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[4, 2, 1, 3, 6] [4, 2, 1, 3, 6, 5]output5node
  8. output ← [4, 2, 1, 3, 6, 5, 7]

    16end17def preorder(node, output); return if node.nil?; output << node.value; preorder(node.left, output); preorder(node.right, output); end18output = []
    values this step[4, 2, 1, 3, 6, 5] [4, 2, 1, 3, 6, 5, 7]output7node
  9. class Node

    1class Node2  attr_accessor :value, :left, :right
    values this step[4, 2, 1, 3, 6, 5, 7]output

Complexity

  • Time: O(n)
  • Space: O(h) recursion stack

Implementation notes

  • Node is the same Ruby class shape as the tree-build lesson, with attr_accessor :value, :left, :right and nil for missing children.
  • preorder(node, output) is recursive and returns immediately with return if node.nil?.
  • The method mutates one shared Ruby array, output, instead of returning a new array from each call.
  • Visit happens before either child call: output << node.value, then preorder(node.left, output), then preorder(node.right, output).
  • That call order is visible in the trace as 4, 2, 1, 3, then 6, 5, 7.
  • The output array grows step by step from [] to [4, 2, 1, 3, 6, 5, 7].
  • puts "[#{output.join(', ')}]" formats the final preorder as the bracketed list [4, 2, 1, 3, 6, 5, 7].