Replacing Recursion With a Stack

Stack of PaperIn Jeff Atwood’s infamous FizzBuzz post, he quotes Dan Kegel who mentions.

Less trivially, I’ve interviewed many candidates who can’t use recursion to solve a real problem.

A programmer who doesn’t know how to use recursion isn’t necessarily such a bad thing, assuming the programmer is handy with the Stack data structure. Any recursive algorithm can be replaced with a non-recursive algorithm by using a Stack.

As an aside, I would expect any developer who knew how to use a stack in this way would probably have no problem with recursion.

After all, what is a recursive method really doing under the hood but implicitely making use of the call stack?

I’ll demonstrate a method that removes recursion by explicitely using an instance of the Stack class, and I’ll do so using a common task that any ASP.NET developer might find familiar. I should point out that I’m not recommending that you should or shouldn’t do this with methods that use recursion. I’m merely pointing out that you can do this.

In ASP.NET, a Web Page is itself a control (i.e. the Page class inherits from Control), that contains other controls. And those controls can possibly contain yet other controls, thus creating a tree structure of controls.

So how do you find a control with a specific ID that could be nested at any level of the control hierarchy?

Well the recursive version is pretty straightforward and similar to other methods I've written before.

public Control FindControlRecursively(Control root, string id)
{
  Control current = root;

  if (current.ID == id)
    return current;

  foreach (Control control in current.Controls)
  {
    Control found = FindControlRecursively(control, id);
    if (found != null)
      return found;
  }
  return null;
}

The recursion occures when we call FindControlRecursively within this method. Essentially what is happening (and this is a simplification) when we call that method is that our current execution point is pushed onto the call stack and the runtime starts executing the code for the internal method call. When that method finally returns, we pop our place from the stack and continue executing.

Rather than try to explain, let me just show you the non-recursive version of this method using a Stack.

public Control FindControlSansRecursion(Control root
    , string id)
{
  //seed it.
  Stack<Control> stack = new Stack<Control>();
  stack.Push(root);
    
  while(stack.Count > 0)
  {
    Control current = stack.Pop();
    if (current.ID == id)
      return current;
        
    foreach (Control control in current.Controls)
    {
      stack.Push(control);
    }
  }
  
  //didn’t find it.
  return null;
}

One thing to keep in mind is that both of these implementations assume that we won’t run into a circular reference problem in which a child control contains an ancestor node.

For the System.Web.UI.Control class we safe in making this assumption. If you try and create a circular reference, a StackOverflowException is thrown. The following code demonstrates this point.

Control control = new Control();
control.Controls.Add(new Control());
// This line will throw a StackOverflowException.
control.Controls[0].Controls.Add(control); 

If the hierarchical structure you are using does allow circular references, you’ll have to keep track of which nodes you’ve already seen so that you don’t get caught in any infinitel loops.

What others have said

Requesting Gravatar... DotNetKicks.com Mar 05, 2007 12:52 AM
# Replacing Recursion With a Stack
You've been kicked (a good thing) - Trackback from DotNetKicks.com
Requesting Gravatar... Christopher Bennage Mar 05, 2007 5:59 AM
# re: Replacing Recursion With a Stack
I learned this technique while studying A*.

I couldn't find the reference, but I also recall reading the the Stack approach is more performant.
Requesting Gravatar... Chip Crary Mar 05, 2007 7:09 AM
# re: Replacing Recursion With a Stack
Cool. Thats a great contribution to the discussion. Thanks.
Requesting Gravatar... Jeff Lewis Mar 05, 2007 8:17 AM
# re: Replacing Recursion With a Stack
Rather than collect, then test, here is a minor edit that makes the code a little more performant, by testing and then collecting:

public Control FindControlSansRecursion(Control root, string id)
{
if (root.ID == id)
return root;

//seed it.
Stack<Control> stack = new Stack<Control>();
stack.Push(root);

while(stack.Count > 0)
{
Control current = stack.Pop();

foreach (Control control in current.Controls)
{
if (control.ID == id)
return control;

stack.Push(control);
}
}

//didn’t find it.
return null;
}
Requesting Gravatar... Scott Mar 05, 2007 8:25 AM
# re: Replacing Recursion With a Stack
"so that you don’t get caught in any infinitel loops."

Which would be ironic considering the object you are using and the error that results from infinite loops.

And it would be actual irony, not Alanis Morrisette irony.
Requesting Gravatar... Karthik Mar 05, 2007 9:22 AM
# re: Replacing Recursion With a Stack
Great example Phil. When I read that comment on recursion in Jeff's post, I thought back to the my last use of recursion in the real world and it was, in fact, this exact situation with asp.net. Thanks for providing the non-recursive solution to this problem.

Requesting Gravatar... Micah Dylan Mar 05, 2007 10:17 PM
# re: Replacing Recursion With a Stack
Old school epiphany - I used to write statistical software in C (on DEC OSF) and we used a lot of recursive functions.

Looking at newfangled code like this example just made me realize the main reason why we used so much recursion back then. In C, you didn't have a bunch of fancy dynamic data structures like the Stack type in .Net: C arrays and other memory structures are all static. In other words, you have to know their size AT COMPILE TIME.

What's a programmer to do? Well you take advantage of the fact that the stack frame is itself a dynamic data structure created for you by the compiler. If you don't know how many elements of something you may need to check and/or store while processing at run time a recursive function would cover many cases and you could avoid dealing with nasty dynamic data structures (nasty in C anyway - malloc anyone?). So we recursed the hell out of everything. Probably more than we should have. Please don't send me any my of my code from those days if you have it; I was young and knew not what I did!

So here's a question - is there really a good reason why you'd want to use recursion (and the implicit stack) rather than explicit iteration with an explicit stack given that you (a) achieve the same effects, (b) the latter is usually more performant, (c) an explicit stack is probably easier to read and maintain than using the implicit stack set up by the CLR?
Requesting Gravatar... Haacked Mar 05, 2007 10:38 PM
# re: Replacing Recursion With a Stack
> So here's a question - is there really a good
> reason why you'd want to use recursion

Really great question! Sometimes, I think it's easier to understand the recursive version.

I had to think about the explicit stack version of this method a little bit before writing it. Whereas I wrote the recursive half-asleep, reading Kafka, using my left pinky toe and completely drunk.
Requesting Gravatar... Mike Schinkel Mar 06, 2007 2:34 AM
# re: Replacing Recursion With a Stack
@Phil >> "As an aside, I would expect any developer who knew how to use a stack in this way would probably have no problem with recursion. After all, what is a recursive method really doing under the hood but implicitely making use of the call stack?"

I think that is the key statement in the entire post!
Requesting Gravatar... Reg Braithwaite Mar 07, 2007 7:12 AM
# re: Replacing Recursion With a Stack
Great post!

I would say that anyone who can build a state stack knows recursion.

I'm surprised that recursion is less performant in some languages.

Recursion has issues when the size of the call stack exceeds some arbitrary limit imposed by the language, but for most non-ridiculous uses, like traversing a file system tree, the cost of a function call instead of iterating and calling functions to manipulate your own stack is not meaningful.

Scientists Announce Empirical Evidence for Greenspun's Tenth Rule
Requesting Gravatar... Boris Yeltsin Mar 08, 2007 7:21 AM
# re: Replacing Recursion With a Stack
Very interesting. 25 years of coding and I've used recursion and stacks (especially in assembler) and I never thought about converting one to the other.

I've just used this technique now. I'm really deep in a heavy Javascript DOM-walk function and I didn't want to break out some code into a separate function - so I just used push/pop instead. Nice!
Requesting Gravatar... Evan Mar 10, 2007 8:28 AM
# re: Replacing Recursion With a Stack
I can't quite get my head around it to show you an implementation (too early on a saturday morning), but if you control the tree structure (ie..menu classes, etc, not control collections), you can skip both the stack and recursion by chaining parent/child iterators together..
Requesting Gravatar... Ricardo Stuven Apr 17, 2007 9:43 AM
# re: Replacing Recursion With a Stack
Wizard Book: "Using a Stack to Implement Recursion"
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-31.html#%_sec_5.1.4
Requesting Gravatar... Chris Oct 19, 2007 12:02 AM
# re: Replacing Recursion With a Stack
Hi,

Just to say that at least for modern compiled language, recursion is optmised at compile or runtime (just-in-time) and you will not see any difference between use of recursion and use of stack/loop.

I believe recursion is usually easier to write, to read, hence to maintain. You do not have to manipulate the stack by yourself, the written code is more compact.

As for Javascript, maybe you can get a difference in execution time though, Javascript optimizers are surely less efficient than Java or C#'s.

Cheers,

Christian
Requesting Gravatar... Anonymous Jan 04, 2008 2:14 PM
# re: Replacing Recursion With a Stack
a better way will be to used something like this

if (node.URL != null && node.URL.Contains(node_path))
return true;
Stack<Node> stack = new Stack<Node>();
stack.Push(node);
while (stack.Count > 0) {
Node _node_ = stack.Pop();
for (int i = 0; i < _node_.Nodes.Length; i++){
if (_node_.Nodes[i].URL != null &&
_node_.Nodes[i].URL.Contains(node_path)) {
stack.Clear();
return true;
}
stack.Push(_node_.Nodes[i]);
}
}
stack.Clear();
return false;
Requesting Gravatar... ajit mishra May 09, 2008 3:06 AM
# re: Replacing Recursion With a Stack
i think that it is very immpressiv point.

What do you have to say?

(will show your gravatar)
Please add 7 and 7 and type the answer here: