Programming is hard by Stephan Schmidt

String reversing Part II: Tail Recursion

As several people pointed out in my last post that my version of reversing a string with recursion wasn’t tail recursive despite the fact that I wrongly thought it was. Not that it’s important in the context of a job interview for Java developers, whether one uses tail recursion or not. But I thought nevertheless about a Java tail recursive solution. Reading more about tail recursion in several articles and the comments of the last post, I wrote a new version of the String reversal solution. This time with tail recursion. So as a service to the interested reader:

      public String reverse(String str) {
          if ((null == str) || (str.length()  <= 1)) {
              return str;
          }
          return reverse(str, "");
      }

      private String reverse(String str, String acc) {
        if (str.length() == 0) {
          return acc;
        } else {
          return reverse(str.substring(1), str.charAt(0) + acc);
        }
      }

Tail recursion means, the last call in the recursive function is a call to the function and there is nothing left to do when the recursive call returns. Why tail recursion? With tail recursion it’s easy for the compiler to remove the recursion and drop the growing stack. So with an optimized tail recursive function you will not run out of stack space what you otherwise would quite easily.

Update: For comparison the non-tail recursive solution.

        public String reverse(String str) {
            if ((null == str) || (str.length()  <= 1)) {
                return str;
            }
            return reverse(str.substring(1)) + str.charAt(0);
        }

Update 2: The call stack for the recursive solution for “ABC” would be:

-> reverse(”ABC”)
-> reverse(”BC”) + ‘A’
-> (reverse(”C”) + ‘B’) + ‘A’
-> (”C” + ‘B’) + ‘A’
-> “CB” + ‘A’
-> “CBA”

and for the tail recursive version:
-> reverse(”ABC”, “”)
-> reverse(”BC”, “A”)
-> reverse(”C”, “BA”)
-> reverse(”", “CBA”)
-> “CBA”

Comparing those two the first one increases the stack to a point until it starts to pop the stack. The tail recursive version does not use the stack to keep a “memory” what it has still to do, but calculates the result imediatly. Comparing the source though, in my view the tail recursive version takes all beauty out of the recursive implementation. It nearly looks iterative.

If you liked this post, subscribe to my free full RSS feed.
Filed under: Java, Tail Recursion

You can share this post!
Do you want to tell others about this article? Use the social bookmark icons to submit this artice to the service of your choice. Thanks.

Get free updates by email

If you did like this article you can get free updates with your RSS reader, you can follow me on Twitter or get free update to new posts by email. Enter your email:

 
About the author: Stephan has been working as a head of development and CTO. He has experiences in different technologies since 20 years including Java, Rails and Python. Stephans main field of interest is maintainablity and productivity in software development. Want to know more? All views are only his own.

Comments

mccoyn

I agree, tail recursion optimizations take the beauty out of recursion. Some things can be solved very beautifully with recursion until you realize the stack frame or speed implications make it an unscaleable solution.

I know a lot of interpreted languages represent the stack as a linked list, or even a linked tree. This gets around the limits on stack space, but makes function calls a little slower.

I haven’t seen any compliers that attempt to make recursion faster other than with the tail-recursion optimization.

stephan

Reading through lambda the ultimate some compilers seem to automatically change recursion to tail recursion, so the beauty in the source is preserved. But I’m no specialist in functional programming.

Hi Stephan,

Kudo’s for following up with the tail recursion example. Personally, unless your a LISPer, I find that tail recursive solutions are better expressed iteratively.

But thats just my opinion, and its been considered faulty before :)

stephan

;-)

[...] A Recursive version from here [...]

Javier Mena

I was intensive tail recursion use in java, but I “discovered” that sun jvm (at least for java 1.5) doesn’t optimizes for tail recursion.

Try to implement a recursive fact with a large number, and it will raise a stack overflow exception.

There are many developers that don’t understand tail recursion. :(

Leave a Reply