Complejidad de algoritmos recursivos

Documentos relacionados
UNIVERSIDAD DE LOS ANDES NUCLEO UNIVERSITARIO RAFAEL RANGEL (NURR) DEPARTAMENTO DE FISICA Y MATEMATICA AREA COMPUTACION TRUJILLO EDO.

Alonso Ramírez Manzanares Computación y Algoritmos 10.03

Tema 3. Análisis de costes

Agradecimientos. Nota de los autores. 1 Problemas, algoritmos y programas 1

Problemas de Recursividad

Notación Asintótica 2

Análisis de Algoritmos

Carlos A. Rivera-Morales. Precálculo 2

Para las ecuaciones diferenciales ordinarias no lineales no existen métodos generales.

Universidad de Valladolid. Departamento de informática. Campus de Segovia. Estructura de datos Tema 4: Ordenación. Prof. Montserrat Serrano Montero

Funciones Tipos de funciones y Recursividad

Solución - práctico 10

Metodología de la Programación II. Recursividad

Complejidad computacional (Análisis de Algoritmos)

<tipo> Tipo de dato de los elementos del vector

Tema 2. Recursividad. Fundamentos de Programación II. Luís Rodríguez Baena

Tema 5.- Recursividad

DEPARTAMENTO DE MATEMATICAS Y FISICA Matemáticas Discreta

CURSO CERO DE MATEMATICAS. Apuntes elaborados por Domingo Pestana Galván. y José Manuel Rodríguez García

Tema 9. Algoritmos sobre listas. Programación Programación - Tema 9: Algoritmos sobre listas

Tiempo de Ejecución. Midiendo el Tiempo de Ejecución

PROBLEMAS DEL TEMA 7: Subprogramas y Modularidad

1. Ejemplo de clase : La clase Cuenta 2. Uso de la clase Cuenta. 3. Métodos y objetos receptores de mensajes (Importante)

Semana de las Matemáticas e Ingeniería. Desarrollo de algoritmos recursivos empleando la aplicación PseInt

Introducción a los espacios vectoriales

Complejidad de Algoritmos

Analisis de algoritmos

Algoritmos. Medios de expresión de un algoritmo. Diagrama de flujo

Algoritmos de Ordenación

Introducción Supongamos un subconjunto de n elementos X = {e 1,,e n de un conjunto referencial Y, X Y. Dentro de Y se define una relación de orden tot

Objetivos formativos de Álgebra

Programación Dinámica 1

NOTACIÓN O GRANDE. El análisis de algoritmos estima el consumo de recursos de un algoritmo.

Estructuras de Repetición (Repita para)

Estructura de datos. Carrera: SCC Participantes

1. (F, +) es un grupo abeliano, denominado el grupo aditivo del campo.

4.1. Polinomios y teoría de ecuaciones

Mostrar Números Ascendentemente. Soluciones Ejercicios Tema 5. tostring Recursivo de LEG. Suma Recursiva de un Vector (1/3)

Funciones. Parámetros por valor

Algoritmos glotones. mat-151

FICHAS REPASO 3º ESO. Para restar números enteros, se suma al minuendo el opuesto del sustraendo y después se aplican las reglas de la suma.

Análisis y Diseño de Algoritmos Tablas de Hash

Estrategias de Diseño de Algoritmos

Algoritmos y programas. Algoritmos y Estructuras de Datos I

Guía práctica de estudio 03: Algoritmos

a) Factoriza el monomio común. En este caso 6 se puede dividir de cada término:

1. Cuántas sentencias hay en la secuencia principal del siguiente programa?

Unidad II: Análisis semántico

CAPÍTULO 1 INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS

BLOQUE 1. LOS NÚMEROS

La eficiencia de los programas

001. Interpreta correctamente códigos (teléfonos, matrículas, NIF ).

UNIVERSIDAD AUTÓNOMA DE AGUASCALIENTES CENTRO DE CIENCIAS BÁSICAS DEPARTAMENTO DE SISTEMAS ELECTRÓNICOS OBJETIVO GENERAL MÉTODOS DIDÁCTICOS EVALUACIÓN

Sucesiones Introducción

Tipos algebraicos y abstractos. Algoritmos y Estructuras de Datos I. Tipos algebraicos

A = A n. = {a n. Georges E. Alfaro Salazar 1

UNIDAD: ÁLGEBRA Y FUNCIONES ECUACIÓN DE PRIMER GRADO

ax 2 + bx + c = 0, con a 0

Complejidad de los Algoritmos

Métodos para escribir algoritmos: Diagramas de Flujo y pseudocódigo

7.4. UTILIDADES DE LAS PILAS

PRÁCTICA ALGORÍTMICA: EJERCICIOS PROPUESTOS

MÓDULO SE: SISTEMAS DE ECUACIONES

Cuestiones: Ejercicios 2: 1) Qué imprimen los siguientes bucles?

Definición 1 Un semigrupo es un conjunto E provisto de una operación binaria asociativa sobre E, se denota por (E, ).

2^10 2^9 2^8 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0 SUMA

un conjunto cuyos elementos denominaremos vectores y denotaremos por es un espacio vectorial si verifica las siguientes propiedades:

ECUACIONES EN Q (NÚMEROS RACIONALES)

Metodología y Tecnología de la Programación

!MATRICES INVERTIBLES

LA ESTRUCTURA DE DATOS PILA EN JAVA. CLASE STACK DEL API JAVA. EJEMPLO Y EJERCICIOS RESUELTOS. (CU00923C)

TEMA 8: Gestión dinámica de memoria

El determinante de una matriz se escribe como. Para una matriz, el valor se calcula como:

Oriol R oca. M a t L a b FUNCIONES EN MATLAB

Ecuaciones de primer grado o lineales

Programación Estructurada

ÍNDICE INTRODUCCIÓN...13

Isabelle como un lenguaje funcional

Contenidos mínimos del área de matemáticas 1º ESO

Algoritmos de Búsqueda y Ordenamiento

la solución a una ecuación cuadrática solicitando al usuario los términos de dicha ecuación.

Guía de uso de DERIVE. 2) Botones de acceso rápido Al colocar el cursor sobre el botón aparece un recuadro con su función

Programación 1. Tema II. Diseño de programas elementales. Lección 7. Diseño modular y descendente de programas

Forma polar de números complejos (repaso breve)

Control de Flujo. Estructuras de Control! Experiencia Educativa de Algorítmica CONTROL DE FLUJO

Examen escrito de Programación 1. Jueves 5 de febrero de Problema 1 o (3.5 puntos)

TEMA Nº 1. Conjuntos numéricos

El TAD Grafo. El TAD Grafo

Recursividad. Introducción a la programación

TEMA 2. CODIFICACIÓN DE LA INFORMACIÓN

RECURSION. Se deben hacer cuatro preguntas para construir una solución recursiva:

Sistemas de ecuaciones.

ESTRUCTURAS REPETITIVAS

DIVISIBILIDAD: Resultados

Curso de Programación 1

Tema 8: Aplicaciones. Ecuaciones en. diferencias: modelos en tiempo discreto. 1 Modelo de crecimiento exponencial. 2 Sucesión de Fibonacci

Tema 7.- Fundamentos de la Programación Orientada a Objetos

log = = Las ecuaciones de cancelación cuando se aplican las funciones f x = a x y f 1 = log a x, se convierten en:

Algoritmos Recursivos de Búsqueda y Ordenación y sus tiempos

Notas del cursos. Basadas en los prontuarios de MATE 3001 y MATE 3023

Transcripción:

Tema 3. Complejidad de algoritmos recursivos 1. INTRODUCCIÓN... 1 CLASIFICACIÓN DE FUNCIONES RECURSIVAS... 1 DISEÑO DE FUNCIONES RECURSIVAS... 2 2. VENTAJAS E INCONVENIENTES DE LA RECURSIVIDAD... 4 3. CÁLCULO DE LA COMPLEJIDAD... 7 4. PROBLEMAS... 14

1. Introducción Recursividad: técnica con la que un problema se resuelve sustituyéndolo por otro problema de la misma forma pero más simple. Ejemplo: Definición de factorial para n >= 0. 0! = 1 n! = n * (n-1)! si n>0 Es una herramienta muy potente, útil y sencilla. Ciertos problemas se adaptan de manera natural a soluciones recursivas. Clasificación de funciones recursivas Según desde dónde se haga la llamada recursiva: - Recursividad directa: la función se llama a sí misma. - Recursividad indirecta: la función A llama a la función B, y ésta llama a A. Según el número de llamadas recursivas generadas en tiempo de ejecución: - Función recursiva lineal o simple: se genera una única llamada interna. - Función recursiva no lineal o múltiple: se generan dos o más llamadas internas. Página 1

Según el punto donde se realice la llamada recursiva, las funciones recursivas pueden ser: - Final: (Tail recursion): La llamada recursiva es la última instrucción que se produce dentro de la función. - No final: (Nontail recursive function): Se hace alguna operación al volver de la llamada recursiva. Las funciones recursivas finales suelen ser más eficientes (en la constante multiplicativa en cuanto al tiempo, y sobre todo en cuanto al espacio de memoria) que las no finales. (Algunos compiladores pueden optimizar automáticamente estas funciones pasándolas a iterativas.) Ejemplo de función recursiva final: algoritmo de Euclides para calcular el máximo común divisor de dos números enteros positivos. mcd (a, b) = mcd (b, a) = mcd (a-b, b) si a > b mcd (a, b-a) si a < b a si a = b Diseño de funciones recursivas El problema original se puede transformar en otro problema similar más simple. Tenemos alguna manera directa de solucionar problemas triviales. Ejemplo: cálculo del factorial de un número entero no negativo. Página 2

Para que un módulo recursivo sea correcto: 1. Análisis por casos del problema: Existe al menos una condición de terminación en la cual no es necesaria una llamada recursiva. Son los casos triviales que se solucionan directamente. Si n = 0 ó n = 1, el factorial es 1. 2. Convergencia de las llamadas recursivas: Cada llamada recursiva se realiza con un dato más pequeño, de forma que se llegue a la condición de terminación. Factorial (n) = n * Factorial (n-1) En la llamada, n va haciéndose más pequeño, y en algún momento llegará a 0 ó 1. 3. Si las llamadas recursivas funcionan bien, el módulo completo funciona bien: Principio de inducción. Factorial(0) = 1 Factorial(1) = 1 Para n > 1, si suponemos correcto el cálculo del factorial de (n 1), Factorial (n) = n * Factorial (n-1) Ejemplo: las torres de Hanoi. Página 3

Ejemplo (no correcto): escribir en orden inverso los elementos de una lista. void EscribirRevés (Lista L) { DatosLista x; if (!L.VaciaLista()) { L.Resto(L); EscribirRevés(L); L.Primero(x); cout << x << endl; 2. Ventajas e inconvenientes de la recursividad Solución de problemas de manera natural, sencilla, comprensible y elegante. Ejemplo: dado un número entero no negativo, escribir su codificación en binario. void pasarbinario (int N){ if (N < 2) { cout << N; pasarbinario(n/2); cout << N%2; Página 4

Facilidad para comprobar y verificar que la solución es correcta. Inducción matemática. boolean Pertenece (Lista L, DatosLista x) { DatosLista y; if (!L.VaciaLista()) { L.Primero(y); if Iguales(x, y) { return(true); L.Resto(L); return( Pertenece(L, x)); return(false); En general, las soluciones recursivas son más ineficientes en tiempo y espacio que las versiones iterativas, debido a las llamadas a subprogramas, la creación de variables dinámicamente en la pila, la duplicación de variables, etc. Algunas soluciones recursivas repiten cálculos innecesariamente. Ejemplo: cálculo del término n-ésimo de la sucesión de Fibonacci. Fib(n) = 1 si n = 0 ó n = 1 Fib(n) = Fib(n-2) + Fib(n-1) si n > 1 Página 5

En general, cualquier función recursiva se puede transformar en una función iterativa. - Ventaja de la función iterativa: más eficiente en tiempo y espacio. - Desventaja de la función iterativa: en algunos casos, muy complicada; además, suelen necesitarse estructuras de datos auxiliares Si la eficiencia es un parámetro crítico, y la función se va a ejecutar frecuentemente, conviene escribir una solución iterativa. La recursividad se puede simular con el uso de pilas para transformar un programa recursivo en iterativo. Las pilas se usan para almacenar los valores de los parámetros del subprograma, los valores de las variables locales, y los resultados de la función. Ejemplo: cálculo del factorial de 3 1 1 2 2 1 3 3 3 2 6 Página 6

3. Cálculo de la complejidad En un algoritmo recursivo, la función T(n) que establece su tiempo de ejecución viene dada por una ecuación E(n) de recurrencia, donde en la expresión aparece la propia función T. T(n) = E(n), y en E(n) aparece la propia función T. Para resolver ese tipo de ecuaciones hay que encontrar una expresión no recursiva de T. (En algunos casos no es tarea fácil.) Ejemplo: Cálculo del factorial de un entero no negativo. int Fact (int n) { if (n <= 1) return(1); else return( n * Fact(n-1)); Sea T(n) el tiempo de ejecución en el caso peor. Se escribe una ecuación de recurrencia que acota a T(n) superiormente como: T ( n) = c1, T ( n 1) + c 2, si si n 1 n > 1 c 1 : tiempo de ejecución del caso trivial n <=1. Si n>1, el tiempo requerido por Fact puede dividirse en dos partes: - T(n-1): La llamada recursiva a Fact con n-1. - c2: El tiempo de evaluar la condición (n>1) y la multiplicación de n*fact(n-1) Página 7

Para resolver las ecuaciones de recurrencia, se suelen emplear tres métodos: 1. Suponer una solución f(n), y usar la recurrencia para demostrar que T(n) = f(n). La prueba se hace generalmente por inducción sobre n. 2. Sustituir las recurrencias por su igualdad hasta llegar a cierta T(n 0 ) que sea conocida. 3. Usar soluciones generales para ciertas ecuaciones de recurrencia conocidas: Resolución de la ecuación característica. El método que vamos a usar es el segundo. Vamos a calcular siempre una cota superior. Usando el segundo método en el caso del factorial: T(n) = T(n-1) + c 2 = (T(n-2) + c 2 ) + c 2 = T(n-2) + 2*c 2 = = (T(n-3) + c 2 ) + 2*c 2 = T(n-3) + 3*c 2 =.... = T(n-k) + k *c 2 Cuando k = n 1, tenemos que T(n) = T(1) + c 2 *(n-1), y es O(n). Página 8

Ejemplo: Caso 1 int Recursiva1 (int n) { if (n <= 1) return(1); else return(recursiva1(n-1)+ Recursiva1(n-1)); T ( n) = 1, 2 T ( n 1) + 1, si si n 1 n > 1 T(n) = 2*T(n-1) + 1 = = 2*(2*T(n-2) + 1) + 1 = 2 2 *T(n-2) + (2 2-1) =.... = 2 k *T(n-k) + (2 k -1) Para k = n-1, T(n) = 2 n-1 *T(1) + 2 n-1-1, y por tanto T(n) es O(2 n ). Ejemplo: Caso 2 int Recursiva2 (int n) { if (n <= 1) return (1); else return(2 * Recursiva2(n-1)); En este caso, como en el factorial, T(n) es O(n). Página 9

Ejemplo: Caso 3 int Recursiva3 (int n) { if (n <= 1) return (1); else return (2 * Recursiva3(n /2)); T ( n) 1, = T ( n / 2) + 1, si n 1 si n > 1 T(n) = T(n/2) + 1 = = T(n/2 2 ) + 2 =.... = T(n/2 k ) + k Como la ecuación n/2 k = 1 se resuelve para k = log 2 n, tenemos que T(n) = T(1) + log 2 n = 1 + log 2 n, y por tanto T(n) es O(log n). Página 10

Ejemplo: Caso 4 int Recursiva4 (int n, int x) { int i; if (n <= 1) return (1); for (i=1;i<=n;i++) { x = x + 1; return( Recursiva4(n-1, x)); 1, si n 1 T ( n) = T ( n 1) + n, si n > 1 T(n) = T(n-1) + n = (T(n-2) + (n-1)) + n = = ((T(n-3)+(n-2))+(n-1)+n =.... = T(n-k) + i= k 1 0 ( n i) Si k = n-1, T(n) = T(1) + i= n 2 0 ( n i) = 1 + ( i= n 2 0 n n - i= 2 0 i ) = = 1 + n (n-1) (n-2)(n-1)/2. Por tanto, T(n) es O(n 2 ). Otra forma: T(n) = T(n-1) + n = T(n-2) + n + (n-1) =.... = T(n-k) + i n i= n k + 1 Si k = n, T(n) = T(0) + i n i= 1 Por tanto, T(n) es O(n 2 ) Página 11

Aplicación: Búsqueda binaria boolean Búsqueda (Vector A, int iz, int de, TipoElemento x) { int mitad; if (iz > de) return (False); mitad = (iz + de) / 2; if (A[mitad] == x) return(true); else if (A[mitad] > x) return (Búsqueda(A, iz, mitad-1, x)); else return (Búsqueda(A, mitad+1,de,x)); La complejidad de este algoritmo es O(log n). Realmente, la función de búsqueda no tiene por qué tener los parámetros Iz y De. La función original sería: boolean Buscar ( Vector A, TipoElemento x) { return(búsqueda(a, 0, N-1, x)); Aquí se dice que la función Búsqueda está sumergida en Buscar, o que hemos aplicado una inmersión de Búsqueda en Buscar. Se definen inmersiones para que, con los nuevos parámetros, se pueda hacer el diseño recursivo de la función inmersora (la función más general, Búsqueda). Cuál es la complejidad de esta versión de la búsqueda binaria? boolean Búsqueda (Vector A, int iz, int de, TipoElemento x) { int mitad; if ((a[iz]>x) (A[de]<x) (iz > de)) return (False); mitad = (iz + de) / 2; if (A[mitad] == x) return(true); else return ( Búsqueda(A, iz, mitad-1, x) Búsqueda(A, mitad+1,de,x)); Aplicación: Torres de Hanoi Página 12

Aplicación: Ordenación por mezcla (mergesort) void Mezclar(vector A, indice iz, indice de, indice mitad) { vector B; indice k, j, i, h; j = mitad+1; h = iz; i = iz; while ((h <= mitad) && (j <= de)) { if (A[h] <= A[j]) { B[i] = A[h]; h = h + 1; B[i] = A[j]; j = j + 1; i = i + 1; if (h > mitad) for (k = j; k<=de; k++) { B[i] = A[k]; i = i + 1; else for (k = h; k <= mitad; k++) { B[i] = A[k]; i = i + 1 ; for (k = iz; k<= de; k++) A[k] = B[k]; void Ordena(vector A, indice iz, indice de) { indice mitad; if (iz < de) { mitad = (iz + de) % 2; ordena(a, iz, mitad); ordena(a, mitad+1, de); mezclar(a, iz, de, mitad); void MergeSort (vector A, indice n) { Ordena(A, 0, n-1) Página 13

4. Problemas Calcular la complejidad de la función siguiente: int Suma (Lista L, int n) { Lista L1, L2; int x, i; if (n = = 1) { L.Primero(x); return(x); L1.Crear(); L2.Crear(); for (i=1; i<= n; i++) { L.Primero(x); L.Resto(L); if (i <= (n/2)) L1.Insertar(x); else L2.Insertar(x); return( Suma(L1, (n/2)) + Suma(L2,(n/2)); Calcular la complejidad de la función siguiente: int F (int n) { int x, i; if (n <= 1) return(1); for(i=1;i<=n;i++) { x = 1; while (x < n) { x = x*2; return(f(n/2)+f(n/2); Página 14

1.- Diseñar una función recursiva que devuelva la suma de los valores de una pila de enteros. 2.- Función recursiva que liste en orden inverso los elementos de una pila. 3.- Función recursiva que liste en orden inverso los elementos de una cola. 4.- Decimos que una pila P es sombrero de otra pila Q, si todos los elementos de P están en Q, en el mismo orden y en las posiciones más cercanas a la cima de la pila (incluida esta). Por definición la pila vacía es cima de cualquier otra. Diseñar una función que dadas 2 pilas nos diga si una es sombrero de otra. 5.- Implementar la función Borrar (L: Lista; X: DatosLista) de forma recursiva. Esta función eliminará de la lista el elemento tantas veces como éste aparezca. 6.- Diseñar una función que sume 1 a un nº en binario que viene almacenado en una lista, donde el primer elemento de la lista será el bit de menor peso del número. Ejemplo: 1 1 0 1 Número: 1011 + 1 = 1100 7.- Dada una lista de colas, donde da igual el tipo de los elementos, diseñar una función que liste todos los elementos de la estructura. 8.- Dada una matriz como la indicada en la figura y las coordenadas de una posición, diseñar una función que elimine la figura que contiene a esa posición. Ejemplo: 1 2 3 4 5 1 2 3 4 5 1 # # 1 # # 2 # # 2 # 3 # función (3, 4) 3 4 # # 4 5 5 Página 15