15

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.

cjs
  • 25,752
  • 9
  • 89
  • 101
  • The post body 'where recursion was so much better than iteration' suggests that you know that the title is questionable: there are no *necessary* uses of recursion. – AakashM Jun 18 '09 at 09:20
  • Indeed, the title is not perfect: I have just updated the question to show that I understand that. I put quite some thought into this, and couldn't find a better word that properly captures the spirit of the question. Feel free to suggest one. – cjs Jun 19 '09 at 10:12
  • 3
    Recursion brings people to stackoverflow... – ilya n. Jun 19 '09 at 22:59
  • 2
    stackoverflow.com, of course! – ilya n. Jun 19 '09 at 23:00
  • "what was it exactly about your particular use of it that made recursion better than using a library-defined iterator" - I'd bet large amounts of money that the likely implementation of the underlying iterator makes use of recursion to get you an iterable interface. – Russell Leggett Aug 10 '10 at 19:49

9 Answers9

12

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
cjs
  • 25,752
  • 9
  • 89
  • 101
Kevin Montrose
  • 22,191
  • 9
  • 88
  • 137
  • See post and comments upon it for discussion about the word necessary. – cjs Jun 19 '09 at 10:14
  • Answer is in keeping with the question as asked at the time. – Kevin Montrose Jun 19 '09 at 13:14
  • 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. – cjs Jun 20 '09 at 03:10
  • Answer is also in keeping with the current question as asked. – Kevin Montrose Jun 20 '09 at 04:38
  • 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. – cjs Jun 21 '09 at 15:33
  • Amazing how your suggestion quotes almost exactly from the answer as written. – Kevin Montrose Jun 21 '09 at 23:26
  • This is a recursion (sort of), which is used a lot when writing animations with JavaScript: `function repeat(){ /* do things */; requestAnimationFrame(repeat); }` – m93a Jun 09 '17 at 19:58
  • I actually do use iteration with an explicit stack for parsing. It makes more sense because it abstracts away the brace-matching to a separate layer and I don't have to scan back and forth to find what section I need to parse recursively. – Challenger5 Jun 29 '17 at 06:14
9

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
  • 7,168
  • 26
  • 29
  • 4
    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 Jun 18 '09 at 09:36
  • 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. Jun 19 '09 at 22:56
  • 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 Jan 18 '10 at 20:25
  • 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 Jan 20 '10 at 09:38
7

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
  • 27,303
  • 5
  • 81
  • 107
6

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,420
  • 11
  • 10
5

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
  • 18,290
  • 7
  • 46
  • 74
1

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
  • 2,951
  • 2
  • 28
  • 50
1

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
  • 167,383
  • 100
  • 513
  • 979
1

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.
  • 18,398
  • 15
  • 71
  • 89
0

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
  • 23,230
  • 17
  • 71
  • 111