Motivo de la declaración de devolución en la llamada de función recursiva

14

Solo tenía una duda en mi mente. La siguiente subrutina (para buscar un elemento, en una lista, por ejemplo) tiene una declaración de retorno al final:

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

No puedo obtener el significado de la declaración return al final (es decir, return search_list (l-> next, x)). Sería realmente útil si alguien pudiera explicar este concepto, utilizando el modelo de pila.

usuario1369975
fuente
Si el primer término de la lista no es el resultado, busque en el resto de la lista . Esto es lo que hace el último return.
Giorgio
@ Giorgio, ¿por qué no habría sido suficiente una llamada a la función, por qué se necesita un retorno antes de eso?
user1369975
77
Porque necesita devolver el valor que devuelve la función
Esailija
77
Votantes: por favor, tenga en cuenta que, dependiendo de los antecedentes del OP, no es del todo obvio lo que returnhace. De hecho, en lenguajes funcionales (y algunos mixtos, como Scala) return no es necesario : el valor de la función recursiva es el valor de su última expresión. ¡Simplemente escribir search_list(l->next, x)sin returnhubiera funcionado en Scala! El significado de la returndeclaración solo es obvio para los programadores con un trasfondo imperativo.
Andres F.
OP: ¿su fragmento de código está escrito en C?
Andres F.

Respuestas:

19

Una declaración de retorno devuelve un valor al llamante inmediato del marco de llamada de la función actual. En el caso de la recursividad, este llamador inmediato puede ser otra invocación de esa misma función.

En la mayoría de los idiomas, si no usa el valor de retorno de una función que llamó (recursivamente o no), ese valor de retorno se descarta o es un error diagnosticable. Hay algunos idiomas en los que el valor de retorno de la última llamada a la función se reutiliza automáticamente como el valor de retorno de la invocación de la función actual, pero no diferencian entre llamadas a funciones normales y recursivas.

Suponiendo que los valores de retorno no utilizados se descarten silenciosamente, si hubiera escrito el código de esta manera:

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

entonces search_listsolo devolvería un valor definido para una lista vacía (NULL) o si el primer elemento coincide con el valor que está buscando. Tan pronto como la función entra en la llamada recursiva, no sabe cuál será el resultado, porque el resultado de la llamada recursiva se descarta.

Además, promete devolver un valor de su función, pero tiene una ruta (la recursiva) donde no especifica qué valor devolver. Dependiendo del idioma que use, esto generalmente resulta en un diagnóstico obligatorio o en un comportamiento indefinido (que es la abreviatura de: cualquier cosa puede suceder y eso puede cambiar en cualquier momento sin previo aviso. No responsabilice a nadie más que a usted mismo si se arruina) tu presentación más importante). Hay algunas situaciones en las que puede parecer que el valor de retorno faltante funciona, pero eso puede cambiar la próxima vez que ejecute el programa (con o sin recompilación).

Bart van Ingen Schenau
fuente
FWIW, Perl devuelve el resultado de la última expresión automáticamente, lo que creo que significa que reutilizaría el valor de retorno. Pero no lo he tocado en años, así que no estoy seguro de eso.
Bobson
1

Dos cosas; Devolver la lista completa en el caso de que encuentre la "x" que está buscando no necesariamente garantiza el uso de la recursión, pero aparte de eso, considere lo siguiente:

Suponga que está buscando un valor de X = "diciembre", y su lista es el valor numérico de los meses del año, un puntero al mes siguiente y los elementos l-> en la lista son los nombres detallados de meses. (Enero, febrero, ..., diciembre). Necesita los tres retornos para los posibles resultados. El primero, return (NULL) es necesario si la lista no contiene la X que está buscando. El segundo, (return (l)) devuelve la lista, en este caso, informándole que encontró su "x". El último es donde entra en juego el modelo de pila. Las llamadas sucesivas a la función habrían actualizado las variables locales (específicamente, l-> ítems) como esta:

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.
Panhandel
fuente
, gracias por tu ilustración, pero realmente no utilices la última devolución
user1369975
Sin el último retorno, nunca superas el paso 1.
panhandel