lab03

17
Con esta entrada vamos a aprender a realizar un simple ejercicio de recursividad en C. Este ejercicio consiste en la suma de los elementos de un vector (ordenado o sin ordenar) de forma recursiva en lenguaje C. Recursión o recursividad es la forma en la cual se especifica un proceso basado en su propia definición. Siendo un poco más precisos, y para evitar el aparente círculo sin fin en esta definición: Un problema que pueda ser definido en función de su tamaño, sea este N, pueda ser dividido en instancias más pequeñas (< N) del mismo problema y se conozca la solución explícita a las instancias más simples, lo que se conoce como casos base, se puede aplicar inducción sobre las llamadas más pequeñas y suponer que estas quedan resueltas. Para que se entienda mejor a continuación se exponen algunos ejemplos: * Factorial(x: Entero): Sea N := x el tamaño del problema, podemos definir el problema de forma recurrente como x*Factorial(x – 1); como el tamaño de Factorial(x – 1) es menor que N podemos aplicar inducción por lo que disponemos del resultado. El caso base es el Factorial(0) que es 1. * Ordenación por fusión(v: vector): Sea N := tamaño(v), podemos separar el vector en dos mitades. Estas dos mitades tienen tamaño N/2 por lo que por inducción podemos aplicar la ordenación en estos dos subproblemas. Una vez tenemos ambas mitades ordenadas simplemente debemos fusionarlas. El caso base es ordenar un vector de 0 elementos, que está trivialmente ordenado y no hay que hacer nada. En estos ejemplos podemos observar como un problema se divide en varias (>= 1) instancias del mismo problema, pero de tamaño menor gracias a lo cual se puede aplicar inducción, llegando a un punto donde se conoce el resultado (el caso base) Fuente: Wikipedia Si alguien quiere saber más sobre la recursividad, puede leer el artículo entero en la wikipedia. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include #include int main() { int n = 3; int t[] = {1,2,3,4}; printf("Resultado de la suma recursiva: %d", sumaVector(t,n)); return 0; } int sumaVector(int t[], int n){ int r = 0; if(n==0){ r += t[0]; }else{ r = t[n] + sumaVector(t,n-1); } return r; }

description

lab03

Transcript of lab03

Con esta entrada vamos a aprender a realizar un simple ejercicio de recursividad en C. Este ejercicio consiste en la suma de los elementos de un vector (ordenado o sin ordenar) de forma recursiva en lenguaje C.Recursin o recursividad es la forma en la cual se especifica un proceso basado en su propia definicin. Siendo un poco ms precisos, y para evitar el aparente crculo sin fin en esta definicin:Un problema que pueda ser definido en funcin de su tamao, sea este N, pueda ser dividido en instancias ms pequeas (< N) del mismo problema y se conozca la solucin explcita a las instancias ms simples, lo que se conoce como casos base, se puede aplicar induccin sobre las llamadas ms pequeas y suponer que estas quedan resueltas. Para que se entienda mejor a continuacin se exponen algunos ejemplos:* Factorial(x: Entero): Sea N := x el tamao del problema, podemos definir el problema de forma recurrente como x*Factorial(x 1); como el tamao de Factorial(x 1) es menor que N podemos aplicar induccin por lo que disponemos del resultado. El caso base es el Factorial(0) que es 1.* Ordenacin por fusin(v: vector): Sea N := tamao(v), podemos separar el vector en dos mitades. Estas dos mitades tienen tamao N/2 por lo que por induccin podemos aplicar la ordenacin en estos dos subproblemas. Una vez tenemos ambas mitades ordenadas simplemente debemos fusionarlas. El caso base es ordenar un vector de 0 elementos, que est trivialmente ordenado y no hay que hacer nada.En estos ejemplos podemos observar como un problema se divide en varias (>= 1) instancias del mismo problema, pero de tamao menor gracias a lo cual se puede aplicar induccin, llegando a un punto donde se conoce el resultado (el caso base)Fuente: WikipediaSi alguien quiere saber ms sobre la recursividad, puede leer elartculo entero en la wikipedia.12345678910111213141516171819202122

#include#includeint main(){ int n = 3; int t[] = {1,2,3,4}; printf("Resultado de la suma recursiva: %d", sumaVector(t,n)); return 0;}int sumaVector(int t[], int n){ int r = 0; if(n==0){ r += t[0]; }else{ r = t[n] + sumaVector(t,n-1); } return r;}

Este es el codigo para la realizacin del ejercicio.Este ejercicio no es nada complicado. El caso base es cuando llegamos al ltimo elemento del vector, es decir, como vamos a empezar por el final (posicin n-1), el final de la ejecucin ser cuando lleguemos al principio del vector (n=0).Mientras no lleguemos al principio del vector, sumamos el elemento anterior al que estamos sumando restando en uno la posicin (n-1) en la llamada recursiva.No related posts.

Recursividad

Se dice que algo es recursivo si se define en funcin de s mismo o a s mismo. Tambin se dice que nunca se debe incluir la misma palabra en la definicin de sta. El caso es que las definiciones recursivas aparecen con frecuencia en matemticas, e incluso en la vida real. Un ejemplo: basta con apuntar una cmara al monitor que muestra la imagen que muestra esa cmara. El efecto es verdaderamente curioso, en especial cuando se mueve la cmara alrededor del monitor.En matemticas, tenemos mltiples definiciones recursivas:- Nmeros naturales: (1) 1 es nmero natural. (2) el siguiente nmero de un nmero natural es un nmero natural- El factorial: n!, de un nmero natural (incluido el 0): (1) si n = 0 entonces: 0! = 1 (2) si n > 0 entonces: n! = n (n-1)!Asimismo, puede definirse un programa en trminos recursivos, como una serie de pasos bsicos, opaso base(tambin conocido como condicin de parada), y unpaso recursivo, donde vuelve a llamarse al programa. En un computador, esta serie de pasos recursivos debe ser finita, terminando con un paso base. Es decir, a cada paso recursivo se reduce el nmero de pasos que hay que dar para terminar, llegando un momento en el que no se verifica la condicin de paso a la recursividad. Ni el paso base ni el paso recursivo son necesariamente nicos.Por otra parte, la recursividad tambin puede ser indirecta, si tenemos un procedimiento P que llama a otro Q y ste a su vez llama a P. Tambin en estos casos debe haber una condicin de parada.Existen ciertas estructuras cuya definicin es recursiva, tales como los rboles, y los algoritmos que utilizan rboles suelen ser en general recursivos.Un ejemplo de programa recursivo en C, el factorial:int factorial(int n){ if (n == 0) return 1; return n * factorial(n-1);}Como se observa, en cada llamada recursiva se reduce el valor de n, llegando el caso en el que n es 0 y no efecta ms llamadas recursivas. Hay que apuntar que el factorial puede obtenerse con facilidad sin necesidad de emplear funciones recursivas, es ms, el uso del programa anterior es muy ineficiente, pero es un ejemplo muy claro.A continuacin se expone un ejemplo de programa que utiliza recursin indirecta, y nos dice si un nmero es par o impar. Al igual que el programa anterior, hay otro mtodo mucho ms sencillo de determinar si un nmero es par o impar, basta con determinar el resto de la divisin entre dos. Por ejemplo: si hacemos par(2) devuelve 1 (cierto). Si hacemos impar(4) devuelve 0 (falso). /* declaracion de funciones, para evitar errores */

int par(int n);

int impar(int n);

int par(int n){ if (n == 0) return 1; return impar(n-1);}

int impar(int n){ if (n == 0) return 0; return par(n-1);}En Pascal se hace as (notar el uso de forward):function impar(n : Integer) : Boolean; forward;function par(n : Integer) : Boolean; forward;

function par(n : Integer) : Boolean;begin if n = 0 then par := true else par := impar(n-1)end;

function impar(n : Integer) : Boolean;begin if n = 0 then impar := false else impar := par(n-1)end;Ejemplo: si hacemos la llamada impar(3) hace las siguientes llamadas:par(2)impar(1)par(0) -> devuelve 1 (cierto)Por lo tanto 3 es un nmero impar.

Qu pasa si se hace una llamada recursiva que no termina?Cada llamada recursiva almacena los parmetros que se pasaron al procedimiento, y otras variables necesarias para el correcto funcionamiento del programa. Por tanto si se produce una llamada recursiva infinita, esto es, que no termina nunca, llega un momento en el que no quedar memoria para almacenar ms datos, y en ese momento se abortar la ejecucin del programa. Para probar esto se puede intentar hacer esta llamada en el programa factorial definido anteriormente:factorial(-1);Por supuesto no hay que pasar parmetros a una funcin que estn fuera de su dominio, pues el factorial est definido solamente para nmeros naturales, pero es un ejemplo claro.Cundo utilizar la recursin?Para empezar, algunos lenguajes de programacin no admiten el uso de recursividad, como por ejemplo el ensamblador o el FORTRAN. Es obvio que en ese caso se requerir una solucin no recursiva (iterativa). Tampoco se debe utilizar cuando la solucin iterativa sea clara a simple vista. Sin embargo, en otros casos, obtener una solucin iterativa es mucho ms complicado que una solucin recursiva, y es entonces cuando se puede plantear la duda de si merece la pena transformar la solucin recursiva en otra iterativa. Posteriormente se explicar como eliminar la recursin, y se basa en almacenar en una pila los valores de las variables locales que haya para un procedimiento en cada llamada recursiva. Esto reduce la claridad del programa. An as, hay que considerar que el compilador transformar la solucin recursiva en una iterativa, utilizando una pila, para cuando compile al cdigo del computador.Por otra parte, casi todos los algoritmos basados en los esquemas de vuelta atrs y divide y vencers son recursivos, pues de alguna manera parece mucho ms natural una solucin recursiva.Aunque parezca mentira, es en general mucho ms sencillo escribir un programa recursivo que su equivalente iterativo. Si el lector no se lo cree, posiblemente se deba a que no domine todava la recursividad. Se propondrn diversos ejemplos de programas recursivos de diversa complejidad para acostumbrarse a la recursin.EjercicioLa famosa sucesin de Fibonacci puede definirse en trminos de recurrencia de la siguiente manera:(1) Fib(1) = 1 ; Fib(0) = 0(2) Fib(n) = Fib(n-1) + Fib(n-2) si n >= 2Cuantas llamadas recursivas se producen para Fib(6)?. Codificar un programa que calcule Fib(n) de forma iterativa.Nota: no utilizar estructuras de datos, puesto que no queremos almacenar los nmeros de Fibonacci anteriores a n; s se permiten variables auxiliares.Ejemplos de programas recursivos- Dados dos nmeros a (nmero entero) y b (nmero natural mayor o igual que cero) determinar a^b.int potencia(int a, int b){ if (b == 0) return 1; else return a * potencia(a, b-1);}La condicin de parada se cumple cuando el exponente es cero. Por ejemplo, la evaluacin depotencia(-2, 3)es:potencia(-2, 3) ->(-2) potencia(-2, 2) ->(-2) (-2) potencia(-2, 1) ->(-2) (-2) (-2) potencia(-2, 0) ->(-2) (-2) (-2) 1

y a la vuelta de la recursin se tiene:

(-2) (-2) (-2) 1/=/(-2) (-2) (-2) potencia(-2,0)< (-2) (-2) (-2)/=/(-2) (-2) potencia(-2, 1)= 1, devolver el elemento mayor.int mayor(int numeros[], int posicion){ int aux; if (posicion == 0) return numeros[posicion]; else { aux = mayor(numeros, posicion-1); if (numeros[posicion] > aux) return numeros[posicion]; else return aux; }}...int numeros[5] = {2,4,1,-3,-1};int N = 5;printf("%d\n", mayor(numeros, 4));- Ahora uno un poco ms complicado: dados dos arrays de nmeros enteros A y B de longitud n y m respectivamente, siendo n >= m, determinar si B est contenido en A. Ejemplo:A = {2,3,4,5,6,7,-3}B = {7,-3} -> contenido; B = {5,7} -> no contenido; B = {3,2} -> no contenidoPara resolverlo, se parte del primer elemento de A y se compara a partir de ah con todos los elementos de B hasta llegar al final de B o encontrar una diferencia.A = {2,3,4,5}, B = {3,4}--2,3,4,53,4^En el caso de encontrar una diferencia se desplaza al segundo elemento de A y as sucesivamente hasta demostrar que B es igual a un subarray de A o que B tiene una longitud mayor que el subarray de A.3,4,53,4Visto de forma grfica consiste en deslizar B a lo largo de A y comprobar que en alguna posicin B se suporpone sobre A.Se han escrito dos funciones para resolverlo,contenidoyesSubarray. La primera devuelve cierto si el subarray A y el array B son iguales; tiene dos condiciones de parada: o que se haya recorrido B completo o que no coincidan dos elementos. La segunda funcin es la principal, y su cometido es ir 'deslizando' B a lo largo de A, y en cada paso recursivo llamar una vez a la funcincontenido; tiene dos condiciones de parada: que el array B sea mayor que el subarray A o que B est contenido en un subarray A.int contenido(int A[], int B[], int m, int pos, int desp){ if (pos == m) return 1; else if (A[desp+pos] == B[pos]) return contenido(A,B,m, pos+1, desp); else return 0;}

int esSubarray(int A[], int B[], int n, int m, int desp){ if (desp+m > n) return 0; else if (contenido(A, B, m, 0, desp)) return 1; else return esSubarray(A, B, n, m, desp+1);}...int A[4] = {2, 3, 4, 5};int B[3] = {3, 4, 5};if (esSubarray(A, B, 4, 5, 0)) printf("\nB esta contenido en A");else printf("\nB no esta contenido en A");Hay que observar que el requisito n >= m indicando en el enunciado es innecesario, si m > n entonces devolver falso nada ms entrar en la ejecucin deesSubarray.Este algoritmo permite hacer bsquedas de palabras en textos. Sin embargo existen algoritmos mejores como el de Knuth-Morris-Prat, el de Rabin-Karp o mediante autmatas finitos; estos algoritmos som ms complicados pero mucho ms efectivos.- Dado un array constituido de nmeros enteros y que contiene N elementos siendo N >= 1, devolver el elemento mayor. En este caso escribir un procedimiento, es decir, que el elemento mayor devuelto sea una variable que se pasa por referencia.void mayor(int numeros[], int posicion, int *m){ if (posicion == 0) *m = numeros[posicion]; else { mayor(numeros, posicion-1, m); if (numeros[posicion] > *m) *m = numeros[posicion]; }}...int numeros[5] = {2,4,1,-3,-1};int M;mayor(numeros, 5-1, &M);printf("%d\n", M);

Hay que tener cuidado con dos errores muy comunes: el primero es declarar la variable para que se pase por valor y no por referencia, con lo cual no se obtiene nada. El otro error consiste en llamar a la funcin pasando en lugar del parmetro por referencia una constante, por ejemplo: mayor(numeros, 5-1, 0); en este caso adems se producir un error de compilacin.

- La funcin de Ackermann, siendo n y m nmeros naturales, se define de la siguiente manera:Ackermann(0, n) = n + 1Ackermann(m, 0) = A(m-1, 1)Ackermann(m, n) = A(m-1, A(m, n-1))Aunque parezca mentira, siempre se llega al caso base y la funcin termina. Probar a ejecutar esta funcin con diversos valores de n y m... que no sean muy grandes!. En Internet pueden encontrarse algunas cosas curiosas sobre esta funcin y sus aplicaciones.Ejercicios propuestosNota:para resolver los ejercicios basta con hacer un nico recorrido sobre el array. Tampoco debe utilizarse ningn array auxiliar, pero si se podrn utilizar variables de tipo entero o booleano.- Dado un array constituido de nmeros enteros y que contiene N elementos siendo N >= 1, escribir una funcin que devuelva la suma de todos los elementos mayores que el ltimo elemento del array.- Dado un array constituido de nmeros enteros y que contiene N elementos siendo N >= 1, escribir una funcin que devuelva cierto si la suma de la primera mitad de los enteros del array es igual a la suma de la segunda mitad de los enteros del array.- Dados dos arrays A y B de longitud n y m respectivamente, n >= m cuyos elementos estn ordenados y no se repiten, determinar si todos los elementos de B estn contenidos en A. Recordar que los elementos estn ordenados, de esta manera basta con realizar un nico recorrido sobre cada array.ConclusionesEn esta seccin se ha pretendido mostrar que la recursividad es una herramienta potente para resolver mltiples problemas. Es ms, todo programa iterativo puede realizarse empleando expresiones recursivas y viceversa.

1. int suma (int A[], int n)2. {3. if (n==0)4. return 0;5. else6. return a[n-1]+suma(a,n-1);7. }

Y el menor valor de un arreglo? Es fcil darse una definicin recursiva: el menor elemento de un arreglo que tiene slo 1 elemento es el elemento el menor elemento de un arreglo de n elementos es el menor entre el menor elemento del arreglo considerando solo los primeros (n-1) elementos y el elemento n1. int menor (int A[], int n)2. {3. if (n==1)4. return=A[0];5. else6. return min(A[n-1],menor (A, n-1));7. }

1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2. /* PROGRAMA PRINCIPAL 3. Author: JOSE PINO - SANTIAGO TORTORA4. Dado un vector de N numeros reales y un numero entero k, determinar el k-esimo mayo elemento.5. Se generan dos tipos de algoritmos diferentes para comparar sus tiempos de ejecucin en un tabla.6. 7. El algoritmo1 (seleccin_mayor1) se basa en ordenar por el metodo burbuja los valores de mayor a menor, 8. de este modo los valores mayores quedaran al inicio del arreglo. Luego se ajusta el puntero para que9. k coincida con la posicion del valor en el arreglo.10. 11. El algoritmo2 (seleccin_mayor2) se basa en ajustando el tope al maximo valor asignado. Por ejemplo, si k=112. entonces el mayor de todos es el resultado, si es k es otro valor, se ajusta el tope con el resultado maximo obtenido13. en el recorrido anterior del arreglo.14. 15. 16. 17. */18. 19. #include 20. #include 21. #include 22. 23. //////////////Prototipos////////////////////////////24. void cargarArreglo (int *A, int tam);25. void imprimirKesimos (int *A, int tam, int k);26. int seleccion_mayor1 (int *A, int k, int n);27. int seleccion_mayor2 (int *A, int k, int n);28. ////////////////////////////////////////////////////29. 30. 31. 32. 33. 34. 35. //////////////////////////////////////////FUNCION PRINCIPAL///////////////////////////////////////////////////////////////////////////36. int main () {37. 38. system ("cls");39. int N;40. int k; 41. int maxValorK = 10;//Cantidad maxima de K para el ejemplo, muestra los top 10 del mayor al menor42. 43. 44. for (N = 1000; N