4
\$\begingroup\$

I wrote this recursive function to print a number sequence from x to n and n to x back.

Here is one of the ideas I had to improve it, but it didn't work out (use another ternary operator at the end of the first one):

return x < n ? printNumberSequence(x + 1, n) : n = 0  x > n  
       && x != n ? printNumberSequence(x - 1, n) : n;

However, I do have a working solution below:

#include <iostream>
using namespace std;

int printNumberSequence(int x, int n)
{ //counts from x until n
    cout << x << endl;
    x < n ? printNumberSequence(x + 1, n) : n = 0 ;
    return x > n  && x != n ? printNumberSequence(x - 1, n) : n;
}

int main()
{
    return printNumberSequence(0, 5);
}

I want to know if this way to solve the problem is good and how could I improve that code.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Why would you want to do this recursively? \$\endgroup\$
    – Mast
    Aug 16, 2018 at 9:03
  • \$\begingroup\$ @Mast It is part of an exercise. I got the solution but I want to see if I can improve it. The question is: Can that be done better? I am trying to learn software development \$\endgroup\$
    – EAzevedo
    Aug 16, 2018 at 9:35
  • \$\begingroup\$ @Fix3r, is it important that your implementation must be recursive? Recursion has many downsides in a problem such is this (especially when it can't be eliminated as tail recursion), and the first statement in my review would be, "Don't use recursion for this." On the other hand, if it's a teaching exercise, perhaps the point is to teach where recursion is appropriate and where it's not. \$\endgroup\$ Aug 16, 2018 at 10:41
  • \$\begingroup\$ @TobySpeight It has to be recursive, it is the part of an exercise but I dont think they will mention where it is appropriate and where its not. Could you point out why it is not appropriate in that case? Thank \$\endgroup\$
    – EAzevedo
    Aug 16, 2018 at 11:06
  • 2
    \$\begingroup\$ It's a bit big for a comment, but can't be an answer if recursion is a requirement. Recursion can be problematic because each time you call a function, we need storage for its local variables (including the parameters, and the return address) - normally implemented in the compiler/runtime as a stack. If you have too many recursive invocations in progress, you can run out of stack - known as a stack overflow. So your code will seem to work for reasonable values of n-x, but fail when that becomes significantly larger (actual values will depend on your compiler and OS). \$\endgroup\$ Aug 16, 2018 at 11:57

3 Answers 3

10
\$\begingroup\$

If you print a sequence of numbers from \$x\$ through \$n\$ in increasing order, and then the same sequence in decreasing order, you'll get a row of numbers which starts and ends with \$x\$ and contains an analogous double sequence of numbers \$x+1\ldots n\$ between, right?

For example a sequence from 2 to 5 and back is: 2, sequence from 3 to 5 and back, and 2 again:

2 [3 4 5 5 4 3] 2

So the simplest solution would be a recursion like this:

void printNumberSequence(int x, int n)
{
    cout << x << endl;
    if(x < n) printNumberSequence(x + 1, n);
    cout << x << endl;
}

If you want to avoid doubling the greatest number, e.g. for numbers 2 through 5 you want the output like:

2 3 4 5 4 3 2

just execute the second cout << ... under the if(), that is when you're not at the maximum number:

void printNumberSequence(int x, int n)
{
    cout << x << endl;
    if(x < n)
    {
        printNumberSequence(x + 1, n);
        cout << x << endl;
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Thank you! I got that. I thought I would need to use x-1 to print it backwards too. I just dont really get how the second cout is executed until it gets to null again. \$\endgroup\$
    – EAzevedo
    Aug 16, 2018 at 11:49
7
\$\begingroup\$

Avoid using namespace std

Importing all names of a namespace is a bad habit to get into, and can cause surprise when names like begin and size are in the global namespace. Get used to using the namespace prefix (std is intentionally very short), or importing just the names you need into the smallest reasonable scope.

The exceptions to this rule are namespaces explicitly intended to be imported wholesale, such as the std::literals namespaces.

No need to return a value

The value we return from the recursive function is only ever used for our main()'s exit status. It ultimately returns n, but what we want from main() is 0 for success and non-zero for failure (small positive values work best). So we always end up reporting failure, except when n is zero.

In our case, we don't have any failures we can report, so printNumberSequence() should return void, and main() can always return 0 - we can do that explicitly, or we can just allow execution to run off the end of main() (note that no other function is allowed to do that, though).

\$\endgroup\$
0
\$\begingroup\$

I don't know, if it's intended that the sample code doesn't print n twice. If it is, the solution would be:

void printNumberSequence(int x, int n)
{
  cout << x << endl;
  if (x < n) {
    printNumberSequence(x + 1, n);
    cout << x << endl;
  }
}
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. \$\endgroup\$ Aug 16, 2018 at 10:42
  • \$\begingroup\$ @Toby: I assumed that the first two sentences would show my intentions. It was missing in CiaPlan's correct solution (I would upvote it, if I could), but meanwhile it was added... \$\endgroup\$
    – Kasimir
    Aug 16, 2018 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.