18

I had a homework assignment that asked for a function that uses direct recursion to find the index of the left-most, lowest, negative integer in an array. Additional requirements were for the parameters of the function to be the array and the size and that the return value for no valid value was -999.

I came up with this:

int LowIndexMinNeg(int src[], int size)
{
    if (size == 0)
       return -999;
    int index = LowIndexMinNeg(src, size - 1);

    if (index >= 0)
       return (src[size - 1] < src[index]) ? (size - 1) : index;
    else
       return (src[size - 1] < 0) ? (size - 1) : index;
} 

It works, satisfies the requirements, and got me full credit. Can this be implemented with tail recursion?

It seems to me that since you have to take the result from the recursive call to use in a comparison to decide if you pass that one on or update it that it wouldn't be possible but recursion still ties my brain in knots a it so there might be something obvious that I'm missing.

Note: My homework assignment was already turned in and graded.

Matt
  • 1,513
  • 3
  • 16
  • 32

6 Answers6

5

If you transform the result of recursion before returning, it is not tail recursive.

EDIT: Having said that, if you want to make the function tail recursive:

const int SENTINEL= 0;

int LowIndexMinNeg(int src[], int size, int index)
{
    if (size == 0)
    {
        if (index<0 || src[index]>=0)
            return -999;
        else
            return index;
    }

    int current_index= size - 1;
    int new_index= src[current_index]<=src[index] ? current_index : index;

    return LowIndexMinNeg(src, size - 1, new_index);
} 

And call as LowIndexMinNeg(src, src_size, src_size - 1)

EDIT2: finding the poorly termed leftmost most negative value. You can probably state that as the index of the first most negative value.

EDIT3: removing most of the conditionals, since it's easier to find the index of the lowest value, then check if it's negative.

MSN
  • 53,214
  • 7
  • 75
  • 105
1

I might have a proposal, but of course I had to change the signature :

int LowIndexMinNeg(int src[], int size, int min = -999)
{
  if (size == 0)
    return min;

  const int min_value = (min == -999) ? 0 : src[min];
  return LowIndexMinNeg(src, size - 1, src[size - 1] <= min_value ? size - 1 : min);
}
icecrime
  • 74,451
  • 13
  • 99
  • 111
1

Here's how you might implement that using tail recursion:

int LowIndexMinNeg(int src[], int size, int index = 0, int lowest_index = -999, int lowest_value = 0)
{
    if (index >= size) {
        return lowest_index;
    }
    if (src[index] < lowest_value) {
        return LowIndexMinNeg(src, size, index+1, index, src[index]);
    } else {
        return LowIndexMinNeg(src, size, index+1, lowest_index, lowest_value);
    }
}

This implementation uses default arguments to keep the function all together, but this makes for a messy interface. You can split this into two functions if you like:

static int LowIndexMinNegHelper(int src[], int size, int index, int lowest_index, int lowest_value)
{
    if (index >= size) {
        return lowest_index;
    }
    if (src[index] < lowest_value) {
        return LowIndexMinNegHelper(src, size, index+1, index, src[index]);
    } else {
        return LowIndexMinNegHelper(src, size, index+1, lowest_index, lowest_value);
    }
}


int LowIndexMinNeg(int src[], int size)
{
    return LowIndexMinNegHelper(src, size, 0, -999, 0);
}

In this case, LowIndexMinNegHelper only needs to be a local function (which I've indicated with static above).

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
1

You need to store the lowest number found so far somewhere. With your function you're using the stack to store that.

With a tail recursive function you'll need to store the lowest number found so far elsewhere. e.g:

  • As a global variable (ugh..).
  • As a parameter to the function itself.
  • As a member variable

The requirement you have for your function probably rules out all those, so you're left with something like the code you have, which cannot be written to be tail-recursive.

To get an idea of e.g. the 2 last point:

  int LowIndexMinNeg(int src[], int size,int current_lowest = 0,int lowest_index = 0) {
     if(size == 0)
        return current_lowest == 0 ? -999 : lowest_index;
     int val = src[size - 1] ;
     if(val < 0 && val  < current_lowest) {
        current_lowest = val;
        lowest_index = size -1;
     }
      return LowIndexMin(src,size - 1,current_lowest,lowest_index);
   }

And

struct find_smallest {
  int current_lowest = 0;
  int lowest_index = 0

   int LowIndexMinNeg(int src[], int size) {
     if(size == 0)
        return current_lowest == 0 ? -999 : lowest_index;
     int val = src[size - 1] ;
     if(val < 0 && val  < current_lowest) {
        current_lowest = val;
        lowest_index = size - 1;
     }
      return LowIndexMin(src,size - 1);
   }
};
nos
  • 223,662
  • 58
  • 417
  • 506
Anonym
  • 7,345
  • 8
  • 35
  • 32
  • I am amazed this has been accepted as it doesn't meet the requirements (return the index of the leftmost lowest negative value) – icecrime Nov 09 '10 at 21:31
  • Edited it to do that - but it would be better keeping state about the lowest index . Though this answer seems to actually answer the question ("no you cant do that given the requirements") – nos Nov 09 '10 at 21:45
0

I'm not sure whether the rules for the assignment would have permitted defining an auxiliary function, but that is one standard transformation for achieving tail recursion when the most natural signature of the operation does not permit it. For example:

int LowIndexMinNeg2(int src[], int size, int min)
{
    if (size == 0) return min;
    src--; size--; 
    if (min >= 0) min++;

    if (src[0] < 0
    && (min < 0 || src[0] <= src[min])) 
        min = 0;

    return LowIndexMinNeg2(src, size, min);
} 

int LowIndexMinNeg2(int src[], int size)
{
    return LowIndexMinNeg2(src + size, size, -999);
} 

This version also reverses the order of traversal to make it possible to distinguish a "real" value of 'min' from the 'not found' value. Other, likely more readable, approaches would involve making use of additional accumulators for the actual minimum value (instead of only an index) and/or the current offset into the array (so that traversal can be done in "normal" order. But of course if I were coding something like this for serious use I wouldn't be using recursion in the first place.

mokus
  • 3,490
  • 16
  • 22
0

You could do this with two statics...

int LowIndexMinNeg(int src[], int size)
{
  static int _min = 0;
  static int _index = 0;

  if (size == 0) return -999;
  if (_index == size) return (src[_min] < 0) ? _min : -999;
  if (src[_index] < 0 && src[_index] < src[_min]) _min = _index;
  ++_index;
  return LowIndexMinNeg(src, size);
}
Nim
  • 33,299
  • 2
  • 62
  • 101