Причина повернення заяви в рекурсивному виклику функції


14

Я просто мав сумніви у своєму розумі. Наступна підпрограма (для пошуку елемента, наприклад, у списку) має в кінці висновок:

list *search_list(list *l, item_type x) {
  if (l == NULL) return(NULL);
  if (l->item == x)
    return(l);
  else
    return( search_list(l->next, x) );
}

Я не можу отримати значення оператора return в кінці (тобто повернути search_list (l-> next, x)). Було б дуже корисно, якби хтось міг пояснити це поняття, використовуючи модель стека.


Якщо перший додаток списку не є результатом, перегляньте решту списку . Це те, що returnробить останній .
Джорджіо

@ Джорджо, чому б не вистачило лише функціонального дзвінка, навіщо потрібне повернення до цього?
користувач1369975

7
Тому що вам потрібно повернути значення, яке повертається функцією
Esailija

7
Покірники: будь ласка, розумійте, що залежно від тла ОП, це зовсім не очевидно, що returnробить. Насправді, функціональні мови (а деякі змішані, як-от Скала) return не потрібні : значення рекурсивної функції - це значення її останнього вираження. Просто писати search_list(l->next, x)без returnцього працювало б у Скалі! Сенс returnвисловлювання очевидний лише для програмістів, що мають імперативний досвід.
Андрес Ф.

ОП: ваш фрагмент коду написаний на С?
Андрес Ф.

Відповіді:


19

Оператор повернення передає значення прямому виклику кадру виклику поточної функції. У випадку рекурсії цей негайний абонент може стати ще одним викликом тієї самої функції.

У більшості мов, якщо ви не використовуєте повернене значення функції, яку ви викликали (рекурсивно чи ні), або повернене значення відкидається, або це діагностична помилка. Існують деякі мови, де значення повернення останнього виклику функції автоматично повторно використовується як зворотне значення поточного виклику функції, але вони не розрізняють нормальні та рекурсивні виклики функції.

Припускаючи, що невикористані значення повернення мовчки відкидаються, якщо ви написали такий код:

list *search_list(list *l, item_type x) {
  if (l == NULL) return(NULL);
  if (l->item == x)
    return(l);
  else
    search_list(l->next, x); // no return!
}

то search_listповертає лише визначене значення для порожнього списку (NULL) або якщо перший елемент відповідає значенню, яке ви шукаєте. Як тільки функція переходить у рекурсивний виклик, ви не знаєте, який буде результат, оскільки результат рекурсивного виклику відкидається.

Крім того, ви обіцяєте повернути значення зі своєї функції, але у вас є шлях (рекурсивний), де ви не вказуєте, яке значення повертати. Залежно від мови, якою ви користуєтеся, це зазвичай призводить до обов'язкової діагностики або до невизначеної поведінки (що є скороченням: все може статися, і це може змінитися в будь-який час без попередження. Не тримайте нікого, крім себе відповідальності, якщо він закрутить Ваша найважливіша презентація). Існують деякі ситуації, коли може повернутися відсутнє значення повернення, але це може змінитися наступного разу, коли ви запустите програму (з рекомпіляцією або без неї).


FWIW, Perl автоматично повертає результат останнього виразу, що, на мою думку, означає, що воно повторно використає повернене значення. Але я цього не торкався роками, тому я не впевнений у цьому.
Бобсон

1

Дві речі; Повернення всього списку у випадку, якщо ви знайдете "x", який ви шукаєте, не обов'язково вимагає використання рекурсії, але це убік, врахуйте наступне:

Припустимо, ви шукаєте значення X = "грудень", і ваш список - числове значення місяців року, вказівник на наступний місяць, а l-> пункти у списку - це прописані назви місяців. (Січень, лютий, ..., грудень). Вам потрібні три повернення для можливих результатів. Перше, повернення (NULL) потрібне, якщо список не містить X, який ви шукаєте. Другий, (return (l)) повертає список, в цьому випадку, повідомляючи вам, що ви знайшли своє "x". Останнє, де грає модель стека. Послідовні виклики функції мали б оновлені локальні змінні (зокрема, l-> item):

1: l->item = January
   returns search_list(l->next, x)
2: l->item = February
   returns search_list(l->next, x)
3-11: March, April, May, June, July, August, September, October, November
   all return search_list(l->next, x)
12: l->item = December
  This matches the second if() and returns your list, letting you know you found your search item.

, дякую за вашу ілюстрацію, але дійсно не використовуйте останнє повернення
користувач1369975

Без останнього повернення ти ніколи не
пройдеш
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.