Académique Documents
Professionnel Documents
Culture Documents
Divide y Vencers
Esquema general
Complejidad en tiempo (eficiencia)
Recurrencia General
Ejemplos
2
IDEA:Dividir un problema de tamao n en subproblemas de
tamao menor de tal forma que solucionando dichos
subproblemas podemos construir la solucin del problema
original.
Elementos:
'
> +
1 ) ( ) / (
1 ) 1 (
) (
n n f b n aT
n T
n T
k
b n T conocido y es ) 1 (
7
Eficiencia de los algoritmos DV
8
Ejemplo
Encontrar el mayor y el menor elemento de
un vector
Aproximacin Directa
Aplicar Tcnica Divide y Vencers
9
voidDirectoMaxMin(vector<T>a,T&max,T
&min){
max=min=a[1];
for(inti=2;i<=a.size();i++){
if(a[i]>max)max=a[i];
if(a[i]<min)min=a[i];
}
}
Requiere 2(n-1) comparaciones de elementos!
10
voidDirectoMaxMin(vector<T>a,T&max,T&min)
{
max=min=a[1];
for(inti=2;i<=a.size();i++){
if(a[i]>max)max=a[i];
elseif(a[i]<min)min=a[i];
}
}
Orden creciente => Mejor caso: n-1
Orden decreciente => Peor caso: 2(n-1)
Media: (3n/2) -1
11
Aprox. Divide y Vencers
Para n s 2, hacer 1 comparacion
Para n grande, dividir el conjunto en dos
subconjuntos de tamao menor y obtener el mayor
y menor elemento de cada subconjunto.
Comparar los mayores/menores elementos de los
dos subconjuntos y determinar el mayor/menor de
ambos.
Repetir recursivamente.
12
voidMaxMin(vector<T>a,inti,intj,T&max,T&min)
{if(i==j)max=min=a[i];//Trivial
elseif(i==j1){//Pequeo
if(a[i]<a[j]){max=a[j];min=a[i];}
else{max=a[i];min=a[j];}
}else{//dividePensubproblemas.
Intmed=(i+j)/2;Tmax1,min1;
MaxMin(i,med,max,min);
MaxMin(mid+1,j,max1,min1);
if(max<max1)max=max1;
if(min>min1)min=min1;
}
}
13
Eficiencia de MaxMin
Luego,
T n=
{
1 si n2
2T n/ 22 encasocontrario
}
T nO n
14
2 ) 2 / 3 (
2 2 /
2 2 2
2 ) 2 ( 2
2 4 ) 4 / ( 4
2 ) 2 ) 4 / ( 2 ( 2
2 ) 2 / ( 2 ) (
1
1
1
1
+
+
+
+ +
+ +
+
n
n n
T
n T
n T
n T n T
k k
k
i
i k
2 2
1
2 1
2 1
2
1 1
1
1
k
k
k
i
i
1
1
1
1
2
x
x
x x x
n
n
+ + + +
+
x / 1
15
Resumen
Divide-y-Venceras nos lleva a generar algoritmos
recursivos
En general, se ha de implementar el algoritmo de
forma recursiva
son pocos los casos donde un algoritmo no recursivo es
mejor
Regla general:Balancearlossubproblemas,
hacer que los subproblemas tengan un tamao de
entrada igual
Ver MergeSort, Quicksort
16
MergeSort
Aplicar la tcnica del divide-y-vencers a problemas
de ordenacin
Divide-y-Vencers:
If n=1 terminar (todo conjunto de un elemento esta
ordenado)
If n>1, dividir los elementos en dos o mas conjuntos,
ordenar cada uno de ellos; combinar las soluciones en un
unico conjunto ordenado
Como repartimos los elementos?
17
Mtodo 1
Primeros n-1 elementos en el conjunto A, ltimo
elemento en B
Ordenar A utilizando este esquema de divisin
recursivamente
B est ordenado
Combinar A y B utilizando el mtodo Inserta() (=
insertar en un array ordenado )
Llegamos a la version recursiva del algoritmo de
Insercion()
Numbero de comparaciones: O(n
2
)
18
Mtodo 2
Intentemos repartir los elementos de forma
equitativa entre los dos conjuntos
A toma n/k, B el resto
Ordenar A y B recursivamente
Combinar A y B utilizando el proceso de
mezcla, que combina las dos listas en una
.....(consideremos k=2)
19
MergeSort
MERGESORTA[1 . . n]
1. If n = 1, salir.
2. Recursivamente ordenar
A[ 1 . . n/2] ] y A[ n/2]+1 . . n ] .
3. Merge Mezclar las 2 mitades
ordenadas.
ProcesoClave:MERGE
20
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
21
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
http://theory.lcs.mit.edu/classes/6.046/fall01/
22
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
23
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
24
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
25
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
26
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
27
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
9
28
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
9
20
13
12
11
29
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
9
20
13
12
11
11
30
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
9
20
13
12
11
11
20
13
12
31
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
9
20
13
12
11
11
20
13
12
12
32
Mezclar dos arrays ordenados
20
13
7
2
12
11
9
1
1
20
13
7
2
12
11
9
2
20
13
7
12
11
9
7
20
13
12
11
9
9
20
13
12
11
11
20
13
12
12
Tiempo = O(n) para mezclar
un total de n elementos
(lineal).
33
Ejemplo -- Particin
[10, 4, 6, 3]
[10, 4, 6, 3, 8, 2, 5, 7]
[8, 2, 5, 7]
[10, 4]
[6, 3]
[8, 2]
[5, 7]
[4] [10]
[3][6] [2][8] [5][7]
34
Ejemplo (cont.) -- Combinar
[3, 4, 6, 10]
[2, 3, 4, 5, 6, 7, 8, 10 ]
[2, 5, 7, 8]
[4, 10]
[3, 6]
[2, 8]
[5, 7]
[4] [10]
[3][6] [2][8] [5][7]
35
Anlisis del algoritmo merge sort
MERGESORTA[1 . . n]
1. If n = 1, return.
2. MergeSort A[ 1 . . n/2] ]
3. Merge-Sort A[ n/2]+1 . . n]
4. Merge(Mezclar las 2 mitades)
O(1)
T(n/2) T(n/2)
T(n/2)
O(n)
Caso base : Si n = 1, entonces T(n) = 1
Caso General: Si n>1 entonces T(n) = 2T(n/2) + cn.
36
Arbol de Recursion
T(n) = 2T(n/2) + cn, con c > 0 constante.
cn
cn/4 cn/4 cn/4 cn/4
cn/2
cn/2
O(1)
h = lg n
cn
cn
cn
#hojas = n
O(n)
Total O(n lg n)
37
Cdigo MergeSort
void mergeSort(vector<T> &a, int left, int right)
{ // ordenar a[left:right]
if (left < right)
{// al menos dos elementos
int mid = (left+right)/2; //mitad
mergeSort(a, left, mid);
mergeSort(a, mid + 1, right);
// mezclar en vector auxiliar b
merge(a, b, left, mid, right);
//copiar al vector original a
copy(b, a, left, right);
}
}
38
Quicksort
Propuesto por C.A.R. Hoare en 1962.
Algoritmo Divide y Vencers
Ordena "en el vector" (como insercin o
heapsort, pero no como mergesort).
Muy prctico (con ajustes).
Ordena en O(n lg n) en caso promedio
Ordena O(n
2
) en el peor caso
39
Quicksort
Algoritmo Divide-y-venceras
El vector A[p..r] se particiona en dos subarrays no vacios,
A[p..q] y A[q+1..r]
Invariante: Todos los elementos en A[p..q] son menores que
todos los elementos en A[q+1..r]
Los subarrays son ordenados recursivamente mediante
llamadas a quicksort
Al contrario que mergesort, no tiene paso de combinacion:
s x
x
> x
40
Pseudocodigo de quicksort
QUICKSORT(A, p, r)
if p < r
then q PARTITION(A, p, r)
QUICKSORT(A, p, q1)
QUICKSORT(A, q+1, r)
Llamadainicial: QUICKSORT(A, 1, n)
41
Particion
Claramente, todas los pasos re realizan en la funcin
particion
Modifica el subarray
Resultado final:
Dos subarrays
Todos los valores en el primer subarray s todos los valores en
el segundo
Devuelve el indice del pivote, elemento que separa los
dos subarrays
Como podemos implementar esta funcion?
42
Pseudocodigo Particion
Partition(A, p, r):
Seleccionar un elemento que actue como pivote (cual?)
Construir dos zonas, A[p..i] y A[j..r]
Todo elemento en A[p..i] <= pivote
Todo elemento en A[j..r] >= pivote
Incrementar i hasta A[i] >= pivote
Decrementar j hasta A[j] <= pivote
Swap A[i] y A[j]
Repetir hasta i > j
Devolver j
43
intPartition(vector<T>&a[],intm,intp)
{Tpivote=a[m];inti=m,j=p;
do{
doi++;
while(a[i]<pivote);
doj;
while(a[j]>pivote);
if(i<j)intercambia(a,i,j);
}while(i<j);
a[m]=a[j];a[j]=pivote;
return(j);
}
44
0 6 10 13 5 8 3 2 11
i==2 j==7
0 6 2 13 5 8 3 10 11
i==3 j==6
0 6 2 3 5 8 13 10 11
i==5 j==4
0 5 2 3 6 8 13 10 11
m==1
45
voidQuickSort(vector<T>&a,intp,intq)
{
if(p<q){//Haymasdeunelemento
//dividirPensubproblemas
intj=Partition(a,p,q+1);
//jeslaposiciondelelementopivote
//Resolverlossubproblemas.
QuickSort(p,j1);
QuickSort(j+1,q);
//Nohayquecombinarlassoluciones
}
}
46
Analisis de quicksort
Asume que todos los elementos son
distintos.
En practica, hay mejores tcnicas para
realizar la particin cuando existen
elementos duplicados.
47
Peor-caso de quicksort
Entradas estan ordenadas inversamente
Particion se realiza sobre el elemento
minimo o maximo
Una parte de la particin no tiene elementos
) (
) ( ) 1 (
) ( ) 1 ( ) 1 (
) ( ) 1 ( ) 0 ( ) (
2
n
n n T
n n T
n n T T n T
O
O +
O + + O
O + +
48
n n T
n n n n n T
n n n n T
n n n T
n n T
+ + + + +
+ + + +
+ + +
+ +
O +
1 ... 3 2 ) 1 (
1 2 3 ) 4 (
1 2 ) 3 (
1 ) 2 (
) ( ) 1 (
49
Arbol de recursion del Peor -caso
T(n) = T(0) + T(n1) + cn
50
Arbol de recursion del Peor -caso
T(n) = T(0) + T(n1) + cn
T(n)
51
cn
T(0) T(n1)
Arbol de recursion del Peor -caso
T(n) = T(0) + T(n1) + cn
52
cn
T(0) c(n1)
Arbol de recursion del Peor -caso
T(n) = T(0) + T(n1) + cn
T(0) T(n2)
53
cn
T(0) c(n1)
Arbol de recursion del Peor -caso
T(n) = T(0) + T(n1) + cn
T(0) c(n2)
T(0)
O(1)
54
cn
O(1)
c(n1)
Arbol de recursion del Peor -caso
T(n) = T(0) + T(n1) + cn
O(1)
c(n2)
O(1)
O(1)
( )
2
1
n k
n
k
O
!
`
.
|
O
4 ^ 10 *
5678 1234
12345678
yd yi Y
yd yi
Y
+
4 ^ 10 *
0135 2468
24680135
yd xd yi xd yd xi yi xi
yd xd yi xd yd xi yi xi
yd yi xd xi Y X
* 4 ^ 10 * ] * * [ 8 ^ 10 * *
* 4 ^ 10 * * 4 ^ 10 * * 8 ^ 10 * *
] 4 ^ 10 * [ * ] 4 ^ 10 * [ *
+ + +
+ + +
+ +
Dividir
Combinar
82
Mult. Enteros Largos D&V
En general,
X= xi*10
n/2
+ xd*10
n/2
Y= yi*10
n/2
+ yd*10
n/2
X*Y = (xi*yi)*10
n
+ (xi*yd+xd*yi)*10
n/2
+ xd*yd
83
Divide y Vencers bsico
Funcin DV_bas (X,Y,n) {
if P es pequeo return X*Y;
else {
Obtener xi, xd, yi, yd; //DIVIDIR
z1 = DV_bas (xi,yi,n/2);
z2 = DV_bas (xi,yd,n/2);
z3 = DV_bas (xd,yi,n/2);
z4 = DV_bas (xd,yd,n/2);
aux= Sumar(z2,z3,n); //COMBINAR
z1 = Desplazar_Dcha(z1,n);
aux = Desplazar_Dcha(aux,n/2);
z = Sumar(z1,aux,z4,2n);
return z;
}
}
84
Eficiencia del algoritmo DV_bas
Funcin DV_bas (X,Y,n) {
if P es pequeo return X*Y; O(1)
else {
Obtener xi, xd, yi, yd; O(n)
z1 = DV_bas (xi,yi,n/2); T(n/2)
z2 = DV_bas (xi,yd,n/2); T(n/2)
z3 = DV_bas (xd,yi,n/2); T(n/2)
z4 = DV_bas (xd,yd,n/2); T(n/2)
aux= Sumar(z2,z3,n); O(n)
z1 = Desplazar_Dcha(z1,n); O(n)
aux = Desplazar_Dcha(aux,n/2); O(n)
z = Sumar(z1,aux,z4,2n); O(n)
return z;
}
}
85
Eficiencia del algoritmo DV_bas
T(n) = 4T(n/2) + n
T(n) est en el orden O(n^2)
El cuello de botella est en el nmero de
multiplicaciones de tamao n/2 => 4
Para mejorar la eficiencia necesitamos reducir el nmero
de multiplicaciones que hacemos.
86
Mult. Enteros Largos D&V
Considerar
r = (xi + xd) * (yi + yd) = (xi*yi) + (xi*yd+xd*yi)
+ xd*yd
Luego, podemos calcular
X*Y = p*10
n
+ (r-p-q)*10
n/2
+ q
sumas de n/2
p q
87
Divide y Vencers
Funcin DV (X,Y,n) {
if P es pequeo return X*Y;
else {
Obtener xi, xd, yi, yd; //DIVIDIR
s1 = Sumar(xi,xd,n/2);
s2 = Sumar(yi,yd,n/2);
p = DV (xi,yi,n/2);
q = DV (xd,yd,n/2);
r = DV (s1,s2,n/2);
aux = Sumar(r,-p,-q,n); //COMBINAR
p = Desplazar_Dcha(p,n);
aux = Desplazar_Dcha(aux,n/2);
z = Sumar(p,aux,q);
return z;
}
}
88
Eficiencia Divide y Vencers
T(n) = 3T(n/2) + 8n = 3T(n/2)+O(n)
) ( ) ( ) (
585 . 1 3 log
2
n O n O n T e
2187751.62 100000000 10000
56885.29 1000000 1000
1479.11 10000 100
38.46 100 10
N^1.585 N^2 n
89
Mult. Enteros Largos D&V
Sobre los umbrales:
Si umbral es igual a 1, entonces
D&V (5.000 cifras) => 41 seg.
Clsico (5.000 cifras) => 25 seg
A partir de 32.789 cifras es mejor D&V (15 minutos !!!)
Si umbral es igual a 64
D&V (5.000 cifras) => 6 seg.
D&V(32.789 cifras) =>2 minutos !!
Seleccin umbral es problemtica:
Depende del algoritmo y de la implementacin particular
Se estima empricamente.
90
Algoritmo de Strassens: Muliplicacion de
matrices
Divide y Vencers
Mezclar
Recurrencia
!
`
.
|
-
!
`
.
|
!
`
.
|
h f
g e
d c
b a
u t
s r
dh cg u
df ce t
bh ag s
bf ae r
+
+
+
+
) ( ) (
) ( ) 2 / ( 8 ) (
3
2
n O n T
n n T n T
O +
91
Algoritmo de Strassens: Muliplicacion de
matrices
Recurrencia Strassen
Mezcla Strassen
Mejor (pero no tiene utilidad debido a las
constantes ocultas)
) ( ) ( ) (
) ( ) 2 / ( 7 ) (
81 . 2 7 log
2
n O n O n T
n n T n T
O +
) (
) (
) (
) (
4
3
2
1
e f d P
e d c P
h b a P
h g a P
+
+
) )( (
) )( (
) )( (
7
6
5
g e c a P
h f d b P
h e d a P
+
+
+ +
7 3 1 5
6 2 4 5
4 3
2 1
P P P P u
P P P P r
and
P P t
P P s
+
+ +
+
+
) (
376 . 2
n O