1

My goal is to write a recursive program that reverse the digits of an integer number. When I test the first element, the code works. However, it doesn't work well for the other two cases, e.g. it for reverse(456) it prints 321654 and for reverse(731) it prints 321654137. I think the issue is with the public static variable reverted.

Can someone please help me to understand the problem and fix it?

using System;  
public class Program
{
    public static void Main(string[] args)
    {
        reverse(123);
        reverse(456);
        reverse(731);
    }

    public static int reverted=0;

    public static void reverse(int number)
    {
        if (number!=0)
        {
            int remainder = number % 10;
            reverted = (reverted*10)+remainder;
            reverse(number/10);
        } 
        else
            Console.WriteLine(reverted);
    }
}
user9405863
  • 1,506
  • 1
  • 11
  • 16
FunnyBuzer
  • 313
  • 2
  • 14
  • 3
    *"I think the issue is with the public static variable reverted"* -- What issue? Did the factory ship you a defective integer? Is it out of spec and rubbing against the adjacent line? Figure out on paper what **all** of the variable values should be at each step. Then **step through the code in the debugger** and see where it goes wrong. Then fix it. – 15ee8f99-57ff-4f92-890c-b56153 Apr 13 '18 at 16:40
  • Why have the static shared variable ('reverted') at all? Why not have a local variable? – maccettura Apr 13 '18 at 16:41
  • 1
    The immediate problem is that you don't reset `reverted` between the calls, so it is not `0` again when you start the second example. You would have seen this by _debugging_ your code, which is an important technique when learning to code. – René Vogt Apr 13 '18 at 16:43
  • @RenéVogt yes, I realised immediately that the problem is the reset of `reverted`, but I failed to amend it after `Console.WriteLine(reverted);` – FunnyBuzer Apr 13 '18 at 16:46
  • 2
    It may be weird to use a string method for this, but I think I'd solve this with `.ToString()` and `Array.Reverse` personally. Not with a recursive method. Or ar least just a single loop dividing by 10 and putting into a list. – Nyerguds Apr 13 '18 at 17:43
  • 2
    If you are making a recursive method that mutates a static, you are doing something very, very **very** wrong. – Eric Lippert Apr 13 '18 at 18:04
  • 2
    @Nyerguds: Obviously no sensible person in industry would solve this problem recursively, but no sensible person in industry would be solving this problem in the first place. **The problem given is almost certainly for a class teaching recursion, not a real world example**. Unfortunately, many classes that teach recursion pick problems like this one, that are more easily solved without recursion, and then students come away thinking recursion is confusing and dumb. – Eric Lippert Apr 13 '18 at 18:24

3 Answers3

14

My goal is to write a recursive program that reverse the digits of an integer number.

Since that is a goal that no one in industry would likely wish to attain, odds are good this is for a class. In particular, no sensible person would solve this problem, even if they had it, with recursion. So this is a lousy problem to teach recursion, because the non-recursive solution is so straightforward.

Odds are also good that you do not understand recursion very well. This is in some sense a great exercise because it requires that you use a special technique, called an accumulator, to achieve a recursive solution.

Moreover, your solution, even if you fixed the bug, does not produce the required number. It prints it, and that is completely different. We wish to be able to produce the result, not merely display it.

(This then brings up the interesting question of how to deal with numbers that fit into an int but whose reverses do not, like 1000000009. Let's ignore those issues for the time being.)

So let's start with the basics. Every recursive method has the same structure:

  • Are we in the base case? If yes, return the result.
  • We're not in the base case.
  • Break the problem up into smaller problems
  • Solve each problem recursively
  • Combine the solutions to solve the larger problem
  • Return the result.

Let's naively apply this pattern to your problem and see what happens.

The base case is easy:

  • the reverse of any non-negative number from 0 to 9 is itself.

What's the recursive case? Suppose we have 157

  • Divide the number by ten to get a smaller number, 15
  • Reverse the smaller number -- 51
  • Append the low order digit of the original number as the high order digit of the reversed smaller number, 751 --- wait, how do we do that exactly?

It's not clear how to perform that last operation.

We need to be smarter.

Here's what you do. (I've left out the error checking that rejects negative numbers.)

static int ReverseHelper(int number, int accumulator) =>
  number == 0 ? 
    accumulator : 
    ReverseHelper(number / 10, accumulator * 10 + number % 10);

public static int Reverse(int number) =>
  ReverseHelper(number, 0);

Let's look at some cases.

Suppose number is 0. Then ReverseHelper returns 0, good. Zero works.

Suppose number is 3. Then we call ReverseHelper(3, 0) which calls ReverseHelper(0, 3), which returns 3. One-digit numbers work.

Suppose number is 35. We call ReverseHelper(35, 0), which calls ReverseHelper(3, 5), which calls ReverseHelper(0, 53), which returns 53. Two digit numbers work.

And so on.

Exercise: There is a straightforward way to deal with the problem of reversing an int where the reversal does not fit into an int; what is it?

You see I hope why this technique is called using an accumulator. The desired result is accumulated gradually as the recursion proceeds, and then returned when the recursion reaches its base case.

Now, notice how this technique relates to your original program. You are using a static field as your accumulator. Never do that! Ever! Recursive methods should not depend for their correctness on external state. Instead, pass the value that you will be consuming recursively down into the recursive call to a helper method.

Study this technique carefully. This is a powerful technique for writing recursive programs. In functional languages, such an operation is called fold or reduce; look to those for further inspiration. In C# it is called Aggregate and is used to produce a summary result on a sequence.

The recursive pattern using accumulators is:

  • Are we in the base case? If yes, return the result from the accumulator.
  • We're not in the base case.
  • Break the problem up into smaller problems
  • Solve each problem recursively, by accumulating information about the solution into the accumulator on the recursive calls.
  • Combine the solutions to solve the larger problem
  • Return the result.

Why is this technique so valuable? In C# this is less important, but in the tail recursive functional languages the compiler can often optimize recursive methods that use accumulators into more efficient code than non-tail-recursive methods, so that's something else to research.

It is valuable in C# because tail recursive methods that use accumulators can easily be turned into non-recursive methods by a simple process of program transformation.

Let's see how. We have:

static int ReverseHelper(int number, int accumulator) =>
  number == 0 ? 
    accumulator : 
    ReverseHelper(number / 10, accumulator * 10 + number % 10);

Let's rewrite that as a statement:

static int ReverseHelper(int number, int accumulator)
{
  if (number == 0)
    return accumulator;
  else
    return ReverseHelper(number / 10, accumulator * 10 + number % 10);
  }
}

Now let's make explanatory variables for all the subexpressions:

static int ReverseHelper(int number, int accumulator)
{
  if (number == 0)
    return accumulator;
  else 
  {
    int newNumber = number / 10;
    int newAccumulator = accumulator * 10 + number % 10;
    return ReverseHelper(newNumber, newAccumulator);
  }
}

So far so good. But now we notice that we can turn the whole thing into a loop!

static int ReverseHelper(int number, int accumulator)
{
  while (true) 
  {
    if (number == 0)
      return accumulator;
    else 
    {
      int newNumber = number / 10;
      int newAccumulator = accumulator * 10 + number % 10;
      number = newNumber;
      accumulator = newAccumulator;
      // And now the loop starts over!
    }
  }
}

And of course we see that this now has the form of the straightforward non-recursive solution to the problem.

This should give you a powerful insight into the nature of recursive programs:

  • Every recursive program can be translated into a tail-recursive program, though it is not always easy to see how.
  • Every tail-recursive program can be translated into a non-recursive loop.
  • The converse is also true! Every program with a loop can be translated into a tail-recursive program!

Again, study these simple techniques carefully. Understanding the relationship between recursive and non-recursive programs is a key tool in CS theory.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • thank you very much for your lesson. I was indeed trying to better understand recursion. So far I simply avoided using it, but I realised that sometimes it is useful and I need strong functions to work also in multi-thread environments. I will use this answer as a source :) – FunnyBuzer Apr 14 '18 at 09:10
  • In general, considering the readability and maintainability of the C# code, would you prefer a pure recursive solution, a tail-recursive solution or a non-recursive solution? – Luca Cremonesi Apr 17 '18 at 15:23
3

Try out my method:

public static int reverse(int number, int result = 0, int reminder = 0)
{
    if (number == 0)
    {
        return result * 10 + reminder;
    }
    return reverse(number / 10, result * 10 + reminder, number % 10);
}

Just call the method like reverse(123). The other two parameters result and reminder are optional because they have a default value.

Demo here

EDIT:

Here is a concise version of the code above :

public static int reverse(int number, int result = 0)
{
    if (number == 0)
    {
        return result;
    }
    return reverse(number / 10, result * 10 + number % 10);
}

Or with the use of the ternary operator :

public static int reverse(int number, int result = 0)
{
    return number == 0 ? result : reverse(number / 10, result * 10 + number % 10);
}
Slaven Tojić
  • 2,945
  • 2
  • 14
  • 33
  • 1
    Your solution is good but it could be more concise and have less duplicated code and a simpler interface. See my answer for how you can tighten up your code. – Eric Lippert Apr 13 '18 at 18:31
0

Reverse Input Number Using Recursion

    public static int ReverseRecursive(int number)
    {
        int remainder = number % 10;
        number = number / 10;
        if (number < 1)
            return remainder;
        return ReverseRecursive(number) + remainder * Convert.ToInt32(Math.Pow(10, number.ToString().Length));
    }
Community
  • 1
  • 1