Back to Recursion & Backtracking
Q10Question 10 of 23

Print Numbers 1 to N Using Recursion

Key Concepts
  • Recursion expresses printing 1 to N as a smaller subproblem: print 1 to N-1 then print N
  • The base case stops recursion when the counter reaches zero or exceeds N
  • Printing before the recursive call produces descending order (work on the way down)
  • Printing after the recursive call produces ascending order (work on the way up as the stack unwinds)
  • Each recursive call consumes one stack frame, so very large N risks StackOverflowError
  • This demonstrates preorder vs postorder work placement, the same concept behind tree traversals
  • For production use on large N, a simple loop avoids the stack depth concern entirely

Definition

Recurse first then print for ascending order, or print first then recurse for descending order.
  • Base case – when the counter reaches zero (or exceeds N), the method returns and stops the recursion.
  • Recursive case – does a small piece of work (printing) and calls itself with a smaller input.
  • Ascending order – recurse first, then print. The print happens on the way back up as the stack unwinds, so the smallest number prints first.
  • Descending order – print first, then recurse. The print happens on the way down, so the largest number prints first.
  • Stack depth – each call adds one frame, so depth is N. For very large N, use a loop instead.

Think of the National Bank of India printing numbered receipts for a batch of N transactions. Instead of a loop counter, we say: to print receipts 1 through N, first handle the earlier numbers, then print the current one. By asking the smaller task to finish first and then printing, the receipts come out in neat ascending order from 1 to N.

Understanding the Concepts

What is the problem?

Print all numbers from 1 to N using recursion, not a loop. This is the simplest recursion problem and teaches the fundamental concept that the position of work relative to the recursive call controls the output order.

JAVA
package com.bank.service;

// Task: print receipt numbers 1 through 5
// Expected output: 1 2 3 4 5

How does the ascending version work?

For ascending order, recurse first and then print. The recursive call goes all the way down to the base case before any printing happens. The smallest value prints first when the stack unwinds.

JAVA
package com.bank.service;

public class PrintAscending {

    public static void printNumbers(int current, int n) {
        if (current > n) {
            return; // base case: stop when we pass N
        }
        System.out.print(current + " ");
        printNumbers(current + 1, n); // recurse to next number
    }

    public static void main(String[] args) {
        System.out.println("Ascending 1 to 5:");
        printNumbers(1, 5);
    }
}
TEXT
Ascending 1 to 5:
1 2 3 4 5

How does the descending version work?

For descending order, print first and then recurse with a decreasing counter. Each print happens on the way down into the recursion, so the largest number prints first.

JAVA
package com.bank.service;

public class PrintDescending {

    public static void printNumbers(int n) {
        if (n == 0) {
            return; // base case: nothing to print
        }
        System.out.print(n + " ");
        printNumbers(n - 1); // recurse with smaller n
    }

    public static void main(String[] args) {
        System.out.println("Descending 5 to 1:");
        printNumbers(5);
    }
}
TEXT
Descending 5 to 1:
5 4 3 2 1

How do you flip ascending to descending by moving one line?

With the decreasing counter, swapping the print and recurse lines flips the output order. Recurse first, then print gives ascending; print first, then recurse gives descending.

JAVA
package com.bank.service;

public class FlipOrder {

    // Ascending: recurse first, print after (work on the way up)
    public static void ascending(int n) {
        if (n == 0) return;
        ascending(n - 1);        // recurse first
        System.out.print(n + " "); // print on unwind
    }

    // Descending: print first, recurse after (work on the way down)
    public static void descending(int n) {
        if (n == 0) return;
        System.out.print(n + " "); // print on descent
        descending(n - 1);        // recurse after
    }

    public static void main(String[] args) {
        System.out.print("Ascending:  "); ascending(5);
        System.out.println();
        System.out.print("Descending: "); descending(5);
    }
}
TEXT
Ascending:  1 2 3 4 5
Descending: 5 4 3 2 1

How does the call stack look?

For ascending(3), the call stack builds up three frames before any printing:

  1. ascending(3) calls ascending(2)
  2. ascending(2) calls ascending(1)
  3. ascending(1) calls ascending(0) which returns
  4. Back in ascending(1): print 1
  5. Back in ascending(2): print 2
  6. Back in ascending(3): print 3
JAVA
package com.bank.service;

public class StackTracer {
    public static void ascending(int n, int depth) {
        if (n == 0) return;
        System.out.println("  ".repeat(depth) + "call ascending(" + n + ")");
        ascending(n - 1, depth + 1);
        System.out.println("  ".repeat(depth) + "print " + n);
    }

    public static void main(String[] args) {
        ascending(3, 0);
    }
}
TEXT
call ascending(3)
  call ascending(2)
    call ascending(1)
    print 1
  print 2
print 3

What are the edge cases?

  • N equals 0: base case triggers immediately, nothing is printed.
  • N equals 1: one print, one call to the base case.
  • Negative N: the base case should handle this (return immediately).
  • Very large N: stack overflow risk. Each call adds one frame, so N = 100000 may exceed the default stack size.
JAVA
package com.bank.service;

public class EdgeCases {
    public static void main(String[] args) {
        System.out.print("N=0: ");
        FlipOrder.ascending(0);
        System.out.println("(nothing)");

        System.out.print("N=1: ");
        FlipOrder.ascending(1);
        System.out.println();

        // Large N would cause StackOverflowError
        // FlipOrder.ascending(100000); // do not run
    }
}
TEXT
N=0: (nothing)
N=1: 1

How does this relate to tree traversals?

Doing work before the recursive call is exactly preorder traversal (process node, then children). Doing work after the recursive call is exactly postorder traversal (process children, then node). This simple 1-to-N example makes tree traversals feel natural.

JAVA
package com.bank.service;

public class TraversalAnalogy {
    // Preorder: process BEFORE recursion (like descending print)
    // Postorder: process AFTER recursion (like ascending print)
    // Inorder: process BETWEEN two recursive calls

    // In a binary tree:
    // void preorder(Node n) {
    //     if (n == null) return;
    //     process(n);       // work before
    //     preorder(n.left);
    //     preorder(n.right);
    // }
}

When should you use a loop instead?

For production code printing 1 to N, a simple for loop is better. It uses O(1) stack space, is easier to read, and cannot cause a stack overflow regardless of N. The recursive version is for learning and interview demonstrations.

JAVA
package com.bank.service;

public class LoopVersion {
    public static void main(String[] args) {
        // Production: use a loop
        for (int i = 1; i <= 5; i++) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
TEXT
1 2 3 4 5

What about the banking domain application?

At the National Bank of India, the nightly batch prints transaction receipts in ascending sequence order for the audit file, and the same logic prints a descending countdown of pending steps on the operator console.

JAVA
package com.bank.service;

public class ReceiptPrinter {
    public static void printReceipts(int current, int total) {
        if (current > total) return;
        System.out.println("Receipt #" + current + " for batch settlement");
        printReceipts(current + 1, total);
    }

    public static void main(String[] args) {
        System.out.println("Printing receipts for today's settlements:");
        printReceipts(1, 3);
    }
}
TEXT
Printing receipts for today's settlements:
Receipt #1 for batch settlement
Receipt #2 for batch settlement
Receipt #3 for batch settlement

What are common interview follow-up questions?

  • How do you print ascending with a decreasing counter? (Recurse first, then print.)
  • What happens with N = 100000? (StackOverflowError because of stack depth.)
  • How is this related to tree traversal? (Preorder = work before recursion, postorder = work after.)
  • What is the tail-recursive version? (Print first, then recurse; some languages optimize this but Java does not.)

Visual Overview

DIAGRAM
  Recursion: Print 1 to N

  ascending(3):
  ┌───────────────────────────┐
  │ ascending(3)              │
  │   ascending(2)            │
  │     ascending(1)          │
  │       ascending(0) → return│
  │     print 1 ← unwind     │
  │   print 2 ← unwind       │
  │ print 3 ← unwind         │
  └───────────────────────────┘
  Output: 1 2 3

  descending(3):
  ┌───────────────────────────┐
  │ descending(3)             │
  │   print 3 ← descent      │
  │   descending(2)           │
  │     print 2 ← descent    │
  │     descending(1)         │
  │       print 1 ← descent  │
  │       descending(0) → return│
  └───────────────────────────┘
  Output: 3 2 1

Key Takeaway

Printing numbers from 1 to N with recursion is a small problem that teaches a big idea: the position of the work relative to the recursive call controls the output order. The base case stops the recursion when the counter reaches zero or passes N, and the recursive case does a small piece of work and calls itself on a smaller input.

If you print the current number first and then recurse, the work happens on the way down into the recursion, giving descending order. If you recurse first and print afterward, the work happens on the way back up as the stack unwinds, giving ascending order. Swapping two lines flips the entire output.

The senior insight is that this demonstrates preorder versus postorder work placement, the same concept that drives binary tree traversals. Doing work before the recursive call is preorder, and doing work after is postorder. Understanding this simple example makes those tree traversals feel natural.

In production at the National Bank of India, Rajesh uses a loop for printing receipt sequences because it avoids stack depth concerns entirely. But he teaches juniors the recursive version because it makes the concepts of base case, recursive case, and stack unwinding tangible.

Remember one sentence: work before the recursive call runs on the way down, work after runs on the way up, and swapping the two flips the order.

---

Share
Use ← → arrow keys to navigate