views:

598

answers:

9

I've recently seen in a couple of different places comments along the lines of, "I learned about recursion in school, but have never used it or felt the need for it since then." (Recursion seems to be a popular example of "book learning" amongst a certain group of programmers.)

Well, it's true that in imperative languages such as Java and Ruby[1], we generally use iteration and avoid recursion, in part because of the risk of stack overflows, and in part because it's the style most programmers in those languages are used to.

Now I know that, strictly speaking, there are no "necessary" uses of recursion in such languages: one can always somehow replace recursion with iteration, no matter how complex things get. By "necessary" here, I'm talking about the following:

Can you think of any particular examples of code in such languages where recursion was so much better than iteration (for reasons of clarity, efficiency, or otherwise) that you used recursion anyway, and converting to iteration would have been a big loss?

Recursively walking trees has been mentioned several times in the answers: what was it exactly about your particular use of it that made recursion better than using a library-defined iterator, had it been available?

[1]: Yes, I know that these are also object-oriented languages. That's not directly relevant to this question, however.

+4  A: 

In my work recursion is very rarely used for anything algorithmic. Things like factorials etc are solved much more readably (and efficiently) using simple loops. When it does show up it is usually because you are processing some data that is recursive in nature. For example, the nodes on a tree structure could be processed recursively.

If you were to write a program to walk the nodes of a binary tree for example, you could write a function that processed one node, and called itself to process each of it's children. This would be more effective than trying to maintain all the different states for each child node as you looped through them.

Simon P Stevens
A: 

I have a List of reports. I am using indexers on my class that contains this list. The reports are retrieved by their screen names using the indexers. In the indexer, if the report for that screen name doesn't exist it loads the report and recursively calls itself.

public class ReportDictionary
    {
        private static List<Report> _reportList = null;

        public ReportColumnList this[string screenName]
        {
            get
            {
                Report rc = _reportList.Find(delegate(Report obj) { return obj.ReportName == screenName; });

                if (rc == null)
                {
                    this.Load(screenName);
                    return this[screenName]; // Recursive call
                }
                else
                    return rc.ReportColumnList.Copy();
            }
            private set
            {
                this.Add(screenName, value);
            }
        }

    }

This can be done without recursion using some additional lines of code.

Rashmi Pandit
+1  A: 

It's all about the data you are processing.

I wrote a simple parser to convert a string into a data structure, it's probably the only example in 5 years' work in Java, but I think it was the right way to do it.

The string looked like this:

"{ index = 1, ID = ['A', 'B', 'C'], data = {" +
   "count = 112, flags = FLAG_1 | FLAG_2 }}"

The best abstraction for this was a tree, where all leaf nodes are primitive data types, and branches could be arrays or objects. This is the typical recursive problem, a non-recursive solution is possible but much more complex.

G B
+6  A: 

When you are walking any kind of tree structure, for example

  • parsing a grammar using a recursive-descent parser
  • walking a DOM tree (e.g. parsed HTML or XML)

also, every toString() method that calls the toString() of the object members can be considered recursive, too. All object serializing algorithms are recursive.

mfx
Perfect examples. +1
peSHIr
toString() is not recursive, and serializing is not always recursive. An exception could be a list of lists, or a map of maps, but normally they aren't.
G B
Good general point, but I personally won't do recursion on DOM tree. I dunno, maybe I'm too conservative about "never trust the client's data".
ilya n.
They are different toString() and serialize() methods, unless the structure itself is recursive. Recursion involves calling the same function, not a function with the same name.
Robert Fraser
One can consider every toString() implementation as belonging to the "same" function, since they all override Object.toString(). In a non-OO-language, toString() could be implemented as toString(Object) with a giant type-based dispatch, which would undoubtably be considered recursive.
mfx
+3  A: 

The most well-known example is probably the quicksort algorithm developed by by C.A.R. Hoare.

Another example is traversing a directory tree for finding a file.

Jochen Walter
+1 for the directory traversing. A very common task which is a real pain until you try recursion.
erikkallen
+6  A: 

There are no "necessary" uses of recursion. All recursive algorithms can be converted to iterative ones. I seem to recall a stack being necessary, but I can't recall the exact construction off the top of my head.

Practically speaking, if you're not using recursion for the following (even in imperative languages) you're a little mad:

  1. Tree traversal
  2. Graphs
  3. Lexing/Parsing
  4. Sorting
Kevin Montrose
See post and comments upon it for discussion about the word necessary.
Curt Sampson
Answer is in keeping with the question as asked at the time.
Kevin Montrose
If you wish to try to twist this into a discussion of a question I never intended to ask, go ahead. Otherwise edit your answer appropriately.
Curt Sampson
Answer is also in keeping with the current question as asked.
Kevin Montrose
Only if you deliberately interpret the word "necessary" differently from the way I'd intended. Please interpret "necessary" in this context as shorthand for, "necessary if you want to avoid being considered a little mad, from a practical point of view." In that light, your answer is contradictory.
Curt Sampson
Amazing how your suggestion quotes almost exactly from the answer as written.
Kevin Montrose
A: 

Recursion can always be rewritten as iteration with an external stack. However if you're sure that you don't risk very deep recursion that would lead to stackoverflow, recursion is a very convenient thing.

One good example is traversing a directory structure on a known operating system. You usually know how deep it can be (maximum path length is limited) and therefore will not have a stackoverflow. Doing the same via iteration with an external stack is not so convenient.

sharptooth
+4  A: 

In my opinion, recursive algorithms are a natural fit when the data structure is also recursive.

def traverse(node, function):
    function(this)
    for each childnode in children:
        traverse(childnode, function)

I can't see why I'd want to write that iteratively.

Kylotan
+1  A: 

It was said "anything tree". I may be too cautious, and I know that stacks are big nowadays, but I still won't use recursion on a typical tree. I would, however, do it on a balanced tree.

ilya n.