如果比较取决于返回值,尾递归是否可行?

时间:2010-11-09 20:28:16

标签: c++ recursion tail-recursion

我有一个家庭作业,要求使用直接递归的函数来查找数组中最左边,最低,负整数的索引。附加要求是函数的参数为​​数组和大小,无效值的返回值为-999。

我想出了这个:

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;
} 

它有效,满足要求,并让我充分信任。这可以用尾递归实现吗?

在我看来,既然你必须从递归调用中获取结果来用于比较,以决定你是否通过了那个或更新它,那将是不可能的,但是递归仍然将我的大脑联系在一起因此可能会有一些我不知道的明显事物。

注意:我的家庭作业已经上交并评分。

6 个答案:

答案 0 :(得分:5)

如果在返回之前转换递归结果,则不是尾递归。

编辑:话虽如此,如果你想让函数tail递归:

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);
} 

并拨打LowIndexMinNeg(src, src_size, src_size - 1)

EDIT2:找到最糟糕的最左边最负值。您可以将其作为第一个最负值的索引。

EDIT3:删除大多数条件,因为更容易找到最低值的索引,然后检查它是否为负数。

答案 1 :(得分:1)

我可能有提案,但当然我必须更改签名:

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);
}

答案 2 :(得分:1)

以下是使用尾递归实现的方法:

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);
    }
}

此实现使用默认参数将函数保持在一起,但这会产生一个混乱的接口。如果您愿意,可以将其拆分为两个函数:

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);
}

在这种情况下,LowIndexMinNegHelper只需要是一个本地函数(我在上面用static表示过)。

答案 3 :(得分:1)

您需要存储到目前为止找到的最低数字。使用您的功能,您正在使用堆栈 存储它。

使用尾递归函数,您需要存储到目前为止其他地方找到的最小数字。 e.g:

  • 作为全球变量(呃..)。
  • 作为函数本身的参数。
  • 作为会员变量

你对函数的要求可能会排除所有这些要求,因此你会留下类似你所拥有的代码,这些代码不能被写成尾递归。

了解例如最后一点:

  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);
   }

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);
   }
};

答案 4 :(得分:0)

我不确定赋值规则是否允许定义辅助函数,但这是一个标准转换,用于在操作的最自然签名不允许时实现尾递归。例如:

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);
} 

此版本还会颠倒遍历的顺序,以便能够区分“min”的“真实”值和“未找到”值。其他可能更具可读性的方法将涉及使用额外的累加器用于实际的最小值(而不是仅仅是索引)和/或当前到数组的偏移量(以便遍历可以以“正常”顺序完成。但是当然,如果我正在编写类似这样的东西以供认真使用,我首先不会使用递归。

答案 5 :(得分:0)

你可以用两个静态来做到这一点......

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);
}