Introduction
Printing numbers from 1 to N seems like one of the simplest tasks in programming. Most beginners immediately think of using a for loop or a while loop.
However, interviewers often introduce an interesting constraint:
"Print numbers from 1 to N without using any loop."
Advertisement
This seemingly simple variation becomes an excellent exercise for understanding recursion, particularly how the placement of statements relative to a recursive call affects the program's output.
The entire solution revolves around one important concept:
- Code before the recursive call executes while recursion moves deeper.
- Code after the recursive call executes while recursion returns.
Understanding this idea will help you solve not only this problem but also many recursive tree and graph traversal problems.
In this guide, you'll learn:
- Printing numbers from 1 to N
- Printing numbers from N to 1
- Printing only even or odd numbers
- Printing both ascending and descending sequences in a single recursive function
- Why statement placement changes the output order
The Core Idea: Statement Placement Controls Order
Recursion executes code in two distinct phases:
1. During the Recursive Descent
This is when each function calls itself.
Statements placed before the recursive call execute immediately.
Example:
System.out.print(current + " ");
printNumbers(current + 1, n);
The number is printed before moving to the next recursive call.
2. During the Recursive Unwinding
Once the base case is reached, recursive calls begin returning.
Statements placed after the recursive call execute during this return phase.
Example:
printNumbers(current + 1, n);
System.out.print(current + " ");
Now the numbers are printed while the recursion unwinds.
This single difference completely changes the output order.
Method 1: Printing Numbers from 1 to N
A common beginner assumption is that placing the print statement after the recursive call will print numbers in ascending order.
Let's see what actually happens.
Incorrect Version
public class PrintAscendingRecursion {
static void printNumbers(int current, int n) {
if (current > n) {
return;
}
printNumbers(current + 1, n);
System.out.print(current + " ");
}
public static void main(String[] args) {
int n = 5;
printNumbers(1, n);
}
}
Output
5 4 3 2 1
Why Does This Print in Reverse?
Although the function starts with:
current = 1
nothing is printed immediately.
Instead, the recursive calls continue:
printNumbers(1)
↓
printNumbers(2)
↓
printNumbers(3)
↓
printNumbers(4)
↓
printNumbers(5)
↓
printNumbers(6)
At this point:
current > n
becomes true, so recursion stops.
Only now do the print statements execute while the recursive calls return.
The return order becomes:
5
↓
4
↓
3
↓
2
↓
1
which explains the output.
Correct Version for Ascending Order
To print numbers in ascending order, simply move the print statement before the recursive call.
Java Program
public class PrintAscendingCorrect {
static void printNumbers(int current, int n) {
if (current > n) {
return;
}
System.out.print(current + " ");
printNumbers(current + 1, n);
}
public static void main(String[] args) {
int n = 5;
printNumbers(1, n);
}
}
Output
1 2 3 4 5
Step-by-Step Execution
The recursive calls occur like this:
printNumbers(1)
Prints:
1
then calls:
printNumbers(2)
which prints:
2
and continues until:
printNumbers(6)
reaches the base case.
Because each number is printed before the recursive call, the output naturally appears in ascending order.
Time Complexity
- Time Complexity: O(n)
- Space Complexity: O(n)
Method 2: Printing Numbers from N to 1
Printing numbers in descending order is just as straightforward.
Instead of counting upward, simply begin from N and move toward 1.
Java Program
public class PrintDescendingRecursion {
static void printNumbers(int current) {
if (current == 0) {
return;
}
System.out.print(current + " ");
printNumbers(current - 1);
}
public static void main(String[] args) {
int n = 5;
printNumbers(n);
}
}
Output
5 4 3 2 1
How It Works
The recursion starts with:
current = 5
The function prints:
5
then calls:
printNumbers(4)
The process continues:
5
↓
4
↓
3
↓
2
↓
1
When:
current == 0
the recursion stops.
Alternative Approach
Another way to print numbers from N to 1 is to count upward from 1, but place the print statement after the recursive call.
For example:
static void printNumbers(int current, int n) {
if (current > n) {
return;
}
printNumbers(current + 1, n);
System.out.print(current + " ");
}
Even though the recursion counts upward, the print statements execute during the unwinding phase, producing:
5 4 3 2 1
This demonstrates how statement placement alone can reverse the visible output without changing the direction of recursion.
Time Complexity
- Time Complexity: O(n)
- Space Complexity: O(n)
Method 3: Printing Only Even (or Odd) Numbers Without a Loop
The same recursive structure can easily be extended to print only even or odd numbers.
Instead of printing every number, simply add a conditional check before the print statement.
The recursive traversal itself remains exactly the same.
Java Program (Even Numbers)
public class PrintEvenNumbersRecursion {
static void printEven(int current, int n) {
if (current > n) {
return;
}
if (current % 2 == 0) {
System.out.print(current + " ");
}
printEven(current + 1, n);
}
public static void main(String[] args) {
int n = 10;
printEven(1, n);
}
}
Output
2 4 6 8 10
How It Works
The recursion still visits every number:
1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10
The only difference is the condition:
if (current % 2 == 0)
Numbers satisfying the condition are printed.
All others are skipped.
The traversal itself remains unchanged.
Printing Odd Numbers
Printing odd numbers requires only a small change.
Replace:
current % 2 == 0
with:
current % 2 != 0
Everything else remains exactly the same.
Time Complexity
- Time Complexity: O(n)
- Space Complexity: O(n)
Method 4: Printing Both Ascending and Descending in One Function
One of the most interesting demonstrations of recursion is printing numbers in both directions using a single recursive function.
The trick is simple:
- Print before the recursive call.
- Print again after the recursive call.
Java Program
public class PrintBothDirections {
static void printBoth(int current, int n) {
if (current > n) {
return;
}
System.out.print(current + " ");
printBoth(current + 1, n);
System.out.print(current + " ");
}
public static void main(String[] args) {
int n = 5;
printBoth(1, n);
}
}
Output
1 2 3 4 5 5 4 3 2 1
Why Does This Work?
The first print statement executes while recursion moves deeper.
The second print statement executes while recursion returns.
This means the same function naturally produces:
- Ascending order on the way down.
- Descending order on the way back up.
This beautifully illustrates how recursion executes code in two separate phases.
Time Complexity
- Time Complexity: O(n)
- Space Complexity: O(n)
Why Statement Placement Matters (Call Stack Explained)
To truly understand recursion, it's helpful to trace the function calls.
Suppose we execute:
printBoth(1, 5)
The execution proceeds like this.
printBoth(1, 5)
Print 1
↓
printBoth(2, 5)
printBoth(2, 5)
Print 2
↓
printBoth(3, 5)
printBoth(3, 5)
Print 3
↓
printBoth(4, 5)
printBoth(4, 5)
Print 4
↓
printBoth(5, 5)
printBoth(5, 5)
Print 5
↓
printBoth(6, 5)
Now:
current > n
becomes true.
The base case returns immediately.
Now recursion begins unwinding.
The returning calls execute the second print statement.
Print 5
↓
Print 4
↓
Print 3
↓
Print 2
↓
Print 1
Combining both phases produces:
1 2 3 4 5 5 4 3 2 1
This is why statement placement completely determines the visible output.
Rule to Remember
| Print Statement Location | Output Order |
|---|---|
| Before recursive call | Printed while recursion goes deeper |
| After recursive call | Printed while recursion returns |
This simple rule applies to many recursive algorithms beyond printing numbers.
How Java Handles This Internally (Memory Concept)
Each recursive call creates a new stack frame.
For example:
printNumbers(1)
↓
printNumbers(2)
↓
printNumbers(3)
↓
printNumbers(4)
↓
printNumbers(5)
Every call stores its own local variables, including:
currentn
These values remain in memory until the recursive call completes.
During Recursive Descent
Statements written before the recursive call execute immediately.
Then Java creates another stack frame for the next recursive call.
The stack keeps growing until the base case is reached.
During Recursive Unwinding
Once the deepest call returns, Java removes one stack frame at a time.
As each frame resumes execution, any statements placed after the recursive call are executed.
This explains why:
System.out.print(current);
can produce completely different output depending on whether it appears before or after the recursive call.
Memory Usage
These examples use only primitive int values.
No heap objects are created.
All recursion-related memory usage comes from the JVM call stack.
Because one stack frame is created for every recursive call:
- Time Complexity: O(n)
- Space Complexity: O(n)
Real-Life Analogy: A Relay Race Baton Pass
Imagine a relay race.
Each runner represents one recursive function call.
Printing Before the Recursive Call
Each runner shouts their number before passing the baton.
You hear:
1 2 3 4 5
because every runner announces themselves immediately.
Printing After the Recursive Call
Now imagine each runner waits.
They pass the baton first.
Only after the baton has reached the final runner and starts coming back do they announce their number.
You hear:
5 4 3 2 1
because the announcements occur during the return journey.
Printing Before and After
If every runner shouts:
- once before passing the baton,
- once after receiving confirmation that the race is complete,
the announcements become:
1 2 3 4 5 5 4 3 2 1
This mirrors exactly how recursive functions execute statements placed before and after recursive calls.
Comparison of All Methods
| Method | Print Statement Placement | Output | Time Complexity | Space Complexity | Best Used When |
|---|---|---|---|---|---|
| Print 1 to N | Before the recursive call | 1 2 3 ... N |
O(n) | O(n) | Printing numbers in ascending order |
| Print N to 1 | Before the recursive call (counting down) | N N-1 ... 1 |
O(n) | O(n) | Printing numbers in descending order |
| Print 1 to N (Alternative) | After the recursive call | N N-1 ... 1 |
O(n) | O(n) | Demonstrating recursive unwinding |
| Print Both Directions | Before and after the recursive call | 1...N N...1 |
O(n) | O(n) | Understanding recursion execution order |
Best Practices
- Always determine whether your print statement should execute before or after the recursive call, because this single decision controls the output order.
- Define a clear base case before writing the recursive logic. Without a proper stopping condition, the recursion will continue indefinitely and eventually throw a
StackOverflowError. - Keep recursive methods focused on one responsibility. For example, if you're printing only even numbers, add a simple conditional check rather than creating a completely different recursive structure.
- When learning recursion, manually trace the call stack using small examples such as
n = 3orn = 5. This makes the execution order much easier to understand. - Use recursion only when it improves clarity or when an interviewer explicitly requires a loop-free solution. For simple number printing, a
forloop is generally the more practical choice. - Remember that recursion uses additional stack memory, whereas an iterative solution typically uses constant extra space.
Common Mistakes Beginners Make
1. Placing the Print Statement in the Wrong Location
This is the most common mistake.
Writing:
printNumbers(current + 1, n);
System.out.print(current);
instead of:
System.out.print(current);
printNumbers(current + 1, n);
produces the opposite output order.
2. Forgetting the Base Case
Without a stopping condition:
if (current > n) {
return;
}
the recursive calls never stop.
Eventually, Java throws:
StackOverflowError
3. Assuming the Base Case Must Return a Value
These recursive methods are declared as:
void
Their purpose is printing, not calculating a value.
Therefore, the base case only needs:
return;
4. Not Tracing the Call Stack
Many beginners try to guess the output instead of tracing each recursive call.
Writing down every recursive call and return is often the fastest way to understand recursion.
5. Thinking Recursion Is Always Better
Although recursion is elegant, it is not always the best choice.
For this problem:
- A loop uses O(1) space.
- Recursion uses O(n) stack space.
In production code, an iterative solution is usually preferred unless recursion provides a clear advantage.
Expert Tips for Interviews
A strong interview answer might sound like this:
"To print numbers without using a loop, I use recursion. The placement of the print statement determines the output order. If the print statement comes before the recursive call, the numbers are printed while recursion moves deeper, producing ascending order when counting upward. If the print statement comes after the recursive call, the output appears during the unwinding phase, producing the reverse order. This same idea can even be used to print both ascending and descending sequences within a single recursive function."
Explaining the difference between the descent and unwinding phases of recursion demonstrates a deeper understanding than simply writing the code.
Pros and Cons
Printing Before the Recursive Call
Pros
- ✅ Simple and intuitive
- ✅ Naturally produces ascending order when counting upward
- ✅ Easy to understand
Cons
- ❌ Does not demonstrate the unwinding phase of recursion
Printing After the Recursive Call
Pros
- ✅ Naturally produces the reverse order
- ✅ Demonstrates recursive unwinding clearly
- ✅ Useful for many recursive algorithms
Cons
- ❌ Can be confusing for beginners because the output appears opposite to the counting direction
Printing Before and After the Recursive Call
Pros
- ✅ Demonstrates both phases of recursion
- ✅ Produces ascending and descending sequences together
- ✅ Excellent educational example for understanding the call stack
Cons
- ❌ Less common in real-world applications
- ❌ Slightly harder for beginners to visualize initially
Frequently Asked Questions
1. How do I print numbers from 1 to N in Java without using a loop?
Use recursion and place the print statement before the recursive call.
This prints each number immediately as recursion moves toward the base case.
2. How do I print numbers from N to 1 without using a loop?
You have two common approaches:
- Start from
Nand count downward while printing before the recursive call. - Start from
1and print after the recursive call.
Both approaches produce the same descending output.
3. Why does placing the print statement after the recursive call reverse the output?
Because the statement executes only after the recursive call returns.
The deepest recursive call finishes first, so its print statement executes before the earlier calls, naturally reversing the visible order.
4. Can I print both ascending and descending sequences using one recursive function?
Yes.
Print once before the recursive call and once after it.
The first print executes during recursive descent, while the second executes during recursive unwinding.
5. What is the time complexity of printing numbers recursively?
Each number is processed exactly once.
- Time Complexity: O(n)
6. What is the space complexity compared to a loop?
Recursion requires:
- Space Complexity: O(n)
because each recursive call creates a stack frame.
A loop requires only O(1) extra space.
7. Can I print only even or odd numbers using recursion?
Yes.
Simply add a condition such as:
current % 2 == 0
or
current % 2 != 0
before printing.
The recursive structure remains unchanged.
8. Is "print numbers without using a loop" a common interview question?
Yes.
It is frequently used to test whether a candidate truly understands recursion rather than simply replacing loops with recursive calls.
9. What happens if I forget the base case?
The recursion never terminates.
Eventually, the JVM call stack becomes full and throws:
StackOverflowError
10. Does the base case need to return a value?
No.
These examples use void methods.
The base case simply uses:
return;
to stop further recursive calls.
11. Is recursion more efficient than a loop for this problem?
No.
Both approaches require O(n) time.
However, recursion requires O(n) stack space, while a loop uses only O(1) extra space.
12. Can the "before vs after recursive call" technique be used in other algorithms?
Absolutely.
The same principle is fundamental to many recursive algorithms, including:
- Tree traversals
- Graph traversals
- Depth-first search (DFS)
- Backtracking algorithms
Understanding how recursion executes during both the descent and unwinding phases will help you solve many advanced recursive problems.