Подтвердить что ты не робот

Возможно ли рекурсия хвоста, если сравнение зависит от возвращаемого значения?

У меня было задание домашней работы, в котором попросила функцию, которая использует прямую рекурсию, чтобы найти индекс самого левого, самого низкого и отрицательного целых чисел в массиве. Дополнительные требования были для параметров функции как массива и размера, а возвращаемое значение для допустимого значения было -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;
} 

Он работает, удовлетворяет требованиям и получает полную защиту. Может ли это быть реализовано с хвостовой рекурсией?

Мне кажется, что, поскольку вы должны принять результат от рекурсивного вызова, чтобы использовать его в сравнении, чтобы решить, передаете ли вы его или обновите, что это будет невозможно, но рекурсия все еще связывает мой мозг сучками а это может быть что-то очевидное, что мне не хватает.

Примечание: мое домашнее задание уже было включено и оценено.

4b9b3361

Ответ 1

Вам нужно сохранить наименьшее число, найденное до сих пор. С помощью вашей функции вы используете стек чтобы сохранить это.

С хвостовой рекурсивной функцией вам нужно будет сохранить самое низкое число, найденное до сих пор в другом месте. например:

  • Как глобальная переменная (ugh..).
  • В качестве параметра самой функции.
  • В качестве переменной-члена

Требование, которое у вас есть для вашей функции, вероятно, исключает все это, поэтому у вас осталось что-то вроде кода, который у вас есть, который нельзя записать как хвост-рекурсивный.

Чтобы получить представление о, например, вторая последняя точка:

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

Ответ 2

Если вы вернете результат рекурсии перед возвратом, он не будет рекурсивным.

EDIT: Сказав это, если вы хотите сделать функцию 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: удаление большинства условных обозначений, так как легче найти индекс самого низкого значения, а затем проверить, является ли оно отрицательным.

Ответ 3

У меня могло бы быть предложение, но, конечно, мне пришлось изменить подпись:

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

Ответ 4

Здесь вы можете реализовать это с помощью рекурсии хвоста:

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 выше).

Ответ 5

Я не уверен, разрешили ли правила для назначения определять вспомогательную функцию, но это одно стандартное преобразование для достижения хвостовой рекурсии, когда сама естественная сигнатура операции не позволяет этого. Например:

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" от значения "не найдено". Другие, вероятно, более читаемые подходы будут включать в себя использование дополнительных аккумуляторов для фактического минимального значения (вместо только индекса) и/или текущего смещения в массиве (так что обход может выполняться в "нормальном" порядке. Конечно, если бы я использовал что-то вроде этого для серьезного использования, я бы не использовал рекурсию в первую очередь.

Ответ 6

Вы можете сделать это с помощью двух статики...

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