Вы находитесь на странице: 1из 20

ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS

Capítulo 3: Estrategias de Diseño de Algoritmos (4h)


Universidad de Cuenca
Facultad de Ingeniería
Ma. Fernanda Granda
fernanda.granda@ucuenca.edu.ec

DIVIDE Y VENCERÁS
SEPTIEMBRE 2016

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 1


Contenido
Introducción
Tiempo de Ejecución de un Alg. Divide y vencerás
Reparto de la carga entre los subproblemas
Multiplicación de Enteros de n cifras
Recursos adicionales

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 2


Introducción
Es una técnica de diseño de algoritmos que consiste en resolver un problema a partir de la
solución de subproblemas del mismo tipo, pero de menor tamaño.
Si los subproblemas son todavía relativamente grandes se aplicará de nuevo esta técnica hasta
alcanzar subproblemas lo suficientemente pequeños para ser solucionados directamente.
 Naturalmente sugiere el uso de la recursión en las implementaciones de estos algoritmos.
1. Descomponer el problema en k subproblemas del mismo tipo, pero de menor tamaño,
donde 1 ≤ k ≤ n, cada uno con una entrada de tamaño nk y donde 0 ≤ nk < n. A esta tarea se
le conoce como división.
2. Resolver independientemente todos los subproblemas, bien directamente si son
elementales o bien de forma recursiva.
3. Combinar las soluciones obtenidas en el paso anterior para construir la solución del
problema original.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 3


Divide y Vencerás
 En el caso particular de los algoritmos Divide y Vencerás que contienen sólo una llamada recursiva, es
decir k = 1, hablaremos de algoritmos de simplificación.
Ejemplos son el cálculo del factorial de un número, que sencillamente reduce el problema a otro
subproblema del mismo tipo de tamaño más pequeño o el de la búsqueda binaria en un vector o el que
resuelve el problema del k-ésimo elemento.
 La ventaja de los algoritmos de simplificación es que consiguen reducir el tamaño del problema en
cada paso, por lo que sus tiempos de ejecución suelen ser muy buenos (normalmente de orden
logarítmico o lineal).
 Además pueden admitir una mejora adicional, puesto que en ellos suele poder eliminarse fácilmente la
recursión mediante el uso de un bucle iterativo, lo que conlleva menores tiempos de ejecución y menor
complejidad espacial al no utilizar la pila de recursión, aunque por contra, también en detrimento de la
legibilidad del código resultante.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 4


Tiempo de Ejecución de un Alg. Divide y
vencerás
Por el hecho de usar un diseño recursivo, los algoritmos diseñados mediante la técnica de Divide y
Vencerás van a heredar las ventajas e inconvenientes que la recursión plantea:
Diseño suele ser simple, claro, robusto y elegante, lo que da lugar a una mayor legibilidad y facilidad
de depuración y mantenimiento del código obtenido.
Conlleva normalmente un mayor tiempo de ejecución que los iterativos, además de la complejidad
espacial que puede representar el uso de la pila de recursión.
Desde un punto de vista de la eficiencia de los algoritmos Divide y Vencerás, es muy importante
conseguir que los subproblemas sean independientes, es decir, que no exista solapamiento entre
ellos.
 De lo contrario el tiempo de ejecución de estos algoritmos será exponencial. Como ejemplo pensemos en el
cálculo de la sucesión de Fibonacci, el cual, a pesar de ajustarse al esquema general y de tener sólo dos
llamadas recursivas, tan sólo se puede considerar un algoritmo recursivo pero no clasificarlo como diseño
Divide y Vencerás. Esta técnica está concebida para resolver problemas de manera eficiente y evidentemente
este algoritmo, con tiempo de ejecución exponencial, no lo es.
En cuanto a la eficiencia hay que tener en también en consideración un factor importante durante el
diseño del algoritmo: el número de subproblemas y su tamaño, pues esto influye de forma notable
en la complejidad del algoritmo resultante.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 5


Tiempo de Ejecución de un Alg. Divide y
vencerás
En definitiva, el diseño Divide y Vencerás produce algoritmos recursivos cuyo tiempo de
ejecución (según vimos en el segundo capítulo) se puede expresar mediante una ecuación en
recurrencia del tipo:

donde a, c y k son números reales, n y b son números naturales, y donde a>0, c>0, k≥0 y b>1. El
valor de a representa el número de subproblemas, n/b es el tamaño de cada uno de ellos, y la
expresión cnk representa el coste de descomponer el problema inicial en los a subproblemas y el
de combinar las soluciones para producir la solución del problema original, o bien el de resolver
un problema elemental. La solución a esta ecuación puede alcanzar distintas complejidades.
Recordemos que el orden de complejidad de la solución a esta ecuación es:

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 6


Tiempo de Ejecución de un Alg. Divide y
vencerás
Las diferencias surgen de los distintos valores que pueden tomar a y b, que en definitiva
determinan el número de subproblemas y su tamaño.
Lo importante es observar que en todos los casos la complejidad es de orden polinómico o
polilogarítmico pero nunca exponencial, frente a los algoritmos recursivos que pueden alcanzar
esta complejidad en muchos casos. Esto se debe normalmente a la repetición de los cálculos
que se produce al existir solapamiento en los subproblemas en los que se descompone el
problema original.
Para aquellos problemas en los que la solución haya de construirse a partir de las soluciones de
subproblemas entre los que se produzca necesariamente solapamiento existe otra técnica de
diseño más apropiada, y que permite eliminar el problema de la complejidad exponencial
debida a la repetición de cálculos. Estamos hablando de la Programación Dinámica.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 7


Reparto de la carga entre los
subproblemas
Es importante que la división en subproblemas se haga de la forma más equilibrada posible.
También es interesante tener presente la dificultad y es esfuerzo requerido en cada una de estas
fases va a depender del planteamiento del algoritmo concreto.
Por ejemplo, los métodos de ordenación por Mezcla y Quicksort son dos representantes claros
de esta técnica pues ambos están diseñados siguiendo el esquema presentado: dividir y
combinar.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 8


Multiplicación de Enteros de n cifras
Algoritmo clásico:
1234*5678 = 1234* (5*1000 + 6*100+7*10+8) = 1234*5*1000 + 1234*6*100 + 1234*7*10 +
1234*8
Operaciones básicas:
Multiplicaciones de dígitos: O(1)
Sumas de dígitos: O(1)
Desplazamientos: O(1)
Eficiencia algoritmo: O(n2)

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 9


Multiplicación de Enteros de n cifras
Algoritmo “divide y vencerás” simple
1234 = 12*100 + 34
5678 = 56*100 + 78
1234*5678 = (12*100 + 34)*(56*100 + 78)
= 12*56*10000 + (12*78+34*56)*100 + (34*78)
Idea: Se reduce una multiplicación de 4 cifras a cuatro multiplicaciones de 2 cifras, más tres
sumas y varios desplazamientos.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 10


Multiplicación de Enteros de n cifras
Algoritmo “divide y vencerás” simple
Dividir
X = 12345678 = xi*104 + xd xi=1234 xd=5678
Y = 24680135 = yi*104 + yd yi=2468 yd=0135
Combinar
X*Y = (xi*104 + xd) * (yi*104 + yd)
= xi*yi*108 + (xi*yd+xd*yi)*104 + xd*yd

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 11


Multiplicación de Enteros de n cifras
Algoritmo “divide y vencerás” simple
En general:
X = xi*10n/2 + xd
Y = yi*10n/2 + yd
X*Y = (xi*10n/2 + xd) * (yi*10n/2 + yd)
= xi*yi*10n + (xi*yd+xd*yi)*10n/2 + xd*yd

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 12


Multiplicación de Enteros de n cifras
función multiplica ( función multiplica (X,Y,n) EFICIENCIA
{
if (x*y es pequeño) { O(1)
return X*Y; O(1)
} else {
Obtener xi, xd, yi, yd; // DIVIDIR O(n)
z1 = multiplica (xi, yi, n/2); T(n/2)
z2 = multiplica (xi, yd, n/2); T(n/2)
z3 = multiplica ( xd, yi, n/2); T(n/2)
z4 = multiplica (xd, yd, n/2); T(n/2)
aux = suma(z2,z3); // COMBINAR O(n)
z1 = desplaza_izq desplaza_izq(z1,n); O(n)
aux = desplaza_izq desplaza_izq(aux,n/2); O(n)
z = suma(z1,aux); O(n)
z = suma(z,z4); O(n)
return z; } } O(1)

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 13


Multiplicación de Enteros de n cifras
Algoritmo “divide y vencerás” simple
T(n) = 4T(n/2) + n
Desarrollamos este ejemplo en el cap 2, con un cambio de variable
T(n) = 2n2 – n ∈ O(n2)
El cuello de botella está en el número de multiplicaciones de tamaño n/2.
Para mejorar la eficiencia debemos reducir el número de multiplicaciones necesarias

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 14


Multiplicación de Enteros de n cifras
Algoritmo “divide y vencerás”
X*Y = (xi*104 + xd) * (yi*104 + yd)
= xi*yi*108 + (xi*yd+xd*yi)*104 + xd*yd

r = (xi+xd)*(yi+yd) = xi*yi + (xi*yd+xd*yi) + xd*yd


p = xi*yi
q = xd*yd
X*Y = p*10n + (r-p-q)*10n/2 + q
Luego podemos realizar una multiplicación de tamaño n a partir de 3 multiplicaciones de
tamaño n/2.

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 15


Multiplicación de Enteros de n cifras
función multiplica ( función multiplica (X,Y,n) EFICIENCIA
{
if (x*y es pequeño) { O(1)
return X*Y; O(1)
} else {
Obtener xi, xd, yi, yd; // DIVIDIR O(n) // DIVIDIR
s1 = suma (xi, xd); O(n)
s2 = suma (yi, yd); O(n)
p = multiplicaDV ( xi, yi, n/2); T(n/2)
q = multiplicaDV (xd, yd, n/2); T(n/2)
r = multiplicaDV (s1, s2, n/2); T(n/2)
aux= suma(r, -p, -q); O(n) //COMBINAR
aux = desplaza_izq (aux,n/2); O(n)
p = desplaza_izq(p,n); O(n)
z = suma(p, aux,q); O(n)
return z; } } O(1)

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 16


Multiplicación de Enteros de n cifras
Algoritmo “divide y vencerás”
T(n)=3T(n/2) + n ∈ O(nlog2 3 ) = O (n1.585)

Implementación Básica Implementación Eficiente


Operaciones n2 n1.585
n = 10 0.1 ms 0.04 ms
n = 100 10 ms 1.48 ms
n = 1000 1 segundo 56.9 ms
n = 10000 100 segundos 2.19 segundos

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 17


Otras Aplicaciones
G1: Búsqueda ternaria.
G2: Mediana de dos vectores
G3. Algoritmos de ordenación Mergesort
G4: Exponenciación rápida.
G5: Multiplicación de matrices: Algoritmo de Strassen.
G6: La moda de un vector
G7: El torneo de tenis
G8: La subsecuencia de suma máxima
G9. Algoritmos de ordenación Quicksort

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 18


¿Qué hemos aprendido?

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 19


Recursos adicionales
Revisar ejercicios del enlace: http://www.lcc.uma.es/~av/Libro/CAP3.pdf

PROGRAMACION II: ESTRUCTURA DE DATOS Y ANÁLISIS DE ALGORITMOS - CAPÍTULO III 20

Вам также может понравиться