Raison de l'instruction de retour dans l'appel de fonction récursive


14

J'avais juste un doute dans ma tête. Le sous-programme suivant (pour rechercher un élément, dans une liste, par exemple) a une instruction return à la fin:

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

Je ne peux pas obtenir la signification de l'instruction de retour à la fin (c'est-à-dire retourner la liste de recherche (l-> suivant, x)). Il serait vraiment utile que quelqu'un puisse expliquer ce concept en utilisant un modèle de pile.


Si le premier terme de la liste n'est pas le résultat, recherchez dans le reste de la liste . C'est ce que fait le dernier return.
Giorgio

@ Giorgio, Pourquoi un appel de fonction n'aurait-il pas suffi, pourquoi un retour est-il nécessaire avant cela?
user1369975

7
Parce que vous devez renvoyer la valeur renvoyée par la fonction
Esailija

7
Downvoters: veuillez vous rendre compte que, selon l'arrière-plan de l'OP, ce n'est pas du tout évident return. En fait, dans les langages fonctionnels (et certains mixtes, comme Scala) return n'est pas nécessaire : la valeur de la fonction récursive est la valeur de sa dernière expression. Écrire simplement search_list(l->next, x)sans returnaurait fonctionné à Scala! La signification de la returndéclaration n'est évidente que pour les programmeurs ayant une formation impérative.
Andres F.

OP: votre extrait de code est-il écrit en C?
Andres F.

Réponses:


19

Une instruction return renvoie une valeur à l' appelant immédiat de la trame d' appel de la fonction actuelle. En cas de récursivité, cet appelant immédiat peut être une autre invocation de cette même fonction.

Dans la plupart des langues, si vous n'utilisez pas la valeur de retour d'une fonction que vous avez appelée (récursivement ou non), cette valeur de retour est supprimée ou il s'agit d'une erreur diagnostiquable. Dans certains langages, la valeur de retour du dernier appel de fonction est automatiquement réutilisée en tant que valeur de retour de l'appel de fonction en cours, mais ils ne différencient pas les appels de fonction normaux et récursifs.

En supposant que les valeurs de retour inutilisées soient éliminées en silence, si vous aviez écrit le code comme ceci:

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

alors search_listne retournerait qu'une valeur définie pour une liste vide (NULL) ou si le premier élément correspond à la valeur que vous recherchez. Dès que la fonction passe dans l'appel récursif, vous ne savez pas quel sera le résultat, car le résultat de l'appel récursif est rejeté.

De plus, vous vous engagez à renvoyer une valeur de votre fonction, mais vous avez un chemin (le récursif) où vous ne spécifiez pas quelle valeur renvoyer. Selon la langue que vous utilisez, cela entraîne généralement un diagnostic obligatoire ou un comportement indéfini (ce qui est un raccourci pour: tout peut arriver et cela peut changer à tout moment sans préavis. Ne tenez personne d'autre que vous-même responsable s'il se trompe) votre présentation la plus importante). Il existe certaines situations où la valeur de retour manquante peut sembler fonctionner, mais cela peut changer la prochaine fois que vous exécutez le programme (avec ou sans recompilation).


FWIW, Perl renvoie automatiquement le résultat de la dernière expression, ce qui signifie , je pense , qu'il réutilisera la valeur de retour. Mais je n'y ai pas touché depuis des années, donc je n'en suis pas certain.
Bobson

1

Deux choses; Renvoyer la liste entière dans le cas où vous trouvez le «x» que vous recherchez ne garantit pas nécessairement l'utilisation de la récursivité, mais à part cela, considérez les points suivants:

Supposons que vous recherchez une valeur de X = "décembre" et que votre liste soit la valeur numérique des mois de l'année, un pointeur sur le mois suivant et les éléments l-> de la liste sont les noms épelés des mois. (Janvier, février, ..., décembre). Vous avez besoin des trois retours pour les résultats possibles. Le premier, return (NULL) est nécessaire si la liste ne contient pas le X que vous recherchez. La seconde, (return (l)) retourne la liste, dans ce cas, vous permettant de savoir que vous avez trouvé votre "x". Le dernier est l'endroit où le modèle de pile entre en jeu. Les appels successifs à la fonction auraient mis à jour les variables locales (spécifiquement, l-> item) comme ceci:

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.

, merci pour votre illustration, mais n'utilisez pas vraiment le dernier retour
user1369975

Sans le dernier retour, vous ne passez jamais l'étape 1.
panhandel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.