2.Complejidadenalgoritmositerativosyrecursivos
60
Reglaspracticasparaelcalculodelaeficiencia
Asignacion,operacioneselementalesdeE/Syaritmeticas(paradatosno
estructurados):tiempoconstante❀O(1)
Composicionsecuencialdeinstrucciones:I1����
f1(n)
;I2����
f2(n)
Regladelasuma:O(f1(n)+f2(n))=O(max(f1(n),f2(n)))
Condicionales(casopeor):ifC����fC(n)
I1����
f1(n)
elseI2����
f2(n)
LacomplejidadenelcasopeoresO(max(fC(n),f1(n),f2(n)))
61
Bucles:while(C����fC(n)
)I ����fI(n)
Tiempodeejecuciondeunavuelta:fC(n)+fI(n).Porlaregladelasuma,si
f(n)=max(fC(n),fI(n)),entoncesO(fC(n)+fI(n))=O(f(n))
•Sielnumerodevueltasenelpeorcasoesg(n),entonceslacomplejidaddel
bucleestaraenO(f(n)·g(n))
•Sielcostedecadaiteracionvarıamuchodeunasaotrassepuedehacerun
analisismasfinoconunsumatoriode1ag(n)deloscostesindividualesde
cadavuelta.
Recursion...masadelante.
62
Ejemplo:ordenacionporseleccion
Idea:buscarelmenoryponerloelprimero;buscarelsiguientemenorycolocarlo
elsegundo;...
voidseleccion(intv[],intn){
inti,j,tmp,min;
for(i=0;i<n;i++){//inv:elsubarray0..i-1estaordenado
min=i;
for(j=i+1;j<n;j++)//buscamoselmenordelosrestantes
if(v[j]<=v[min])min=j;
tmp=v[min];//lointercambiamosporeli-esimo
v[min]=v[i];
v[i]=tmp;}
}
seleccionnoesmuysensiblealorden:lacomprobacionv[j]<=v[min]sehace
elmismonumerodevecesencualquiercaso.Lasvariacionesdetiemposolo
sedebenaasignacionesdentrodelcondicional❀nooscilamasdeun15%63
Tiemposdeejecucionconstantesparaoperacionesbasicas(intruccionessimples):
asignacion:cacomparacion:ccincremento:ci
for(i=0;i<n;i++){ca+�n
i=0cc+�n−1
i=0ci
min=i;�n−1
i=0ca
for(j=i+1;j<n;j++)�n−1
i=0(ca+�n
j=i+1cc+�n−1
j=i+1ci)
if(v[j]<=v[min])�n−1
i=0
�n−1j=i+1cc
min=j;�n−1
i=0
�n−1j=i+1ca(*)
tmp=v[min];�n−1
i=0ca
v[min]=v[i];�n−1
i=0ca
v[i]=tmp;}�n−1
i=0ca
En(*)estamossuponiendoquelacondicionsiempreescierta❀peorcaso
64
tA(x)salecomoresultadodesumarcadaunodeloscostesanteriores...difıcilde
manejar.Hagamosalgunassimplificaciones:
Podemossuponerquelasoperacionesdecosteconstanteestanacotadaspor
1(siemprepuedehacerseeligiendoadecuadamentelaunidaddetiempo):
ca=cc=ci=1
Entoncessumandoloscostesobtendrıamosalgodelestilo:
tA(x)=a·n2
+b·n+c
Esdecir,lacomplejidadvienedadaporunpolinomiodesegundogrado❀
O(n2).
Enelcasomedio,elcostedelaasignacionmin=jhabrıaqueponderarlode
acuerdoalaprobabilidaddequefueseciertalacondiciondelif.Noobstante,
comolacondicionseevalua,lacomplejidadsiguesiendodelordenden2.
Estealgoritmoesdelordenden2
encualquiercaso:noessensiblealorden.
65
Engeneral,noesnecesariohacerunanalisistandetallado:podemosfijarnos
enlaoperacionbasicaquemasserepiteuoperacioncaracterıstica.Eneste
casoseraelif(lacondicionasociada)queestadentrodedosfor(obien,si
asumimoselpeorcasoconsideramoslaasignaciondelifmin=j)
Deacuerdoconloanteriortendrıamos:
tA(x)≈
n−1 �
i=0
n−1 �
j=i+1
1=
n−1 �
i=0
(n−i−1)=
n−1 �
i=0
i=(n−1)·n
2
Esdecir,laoperacioncaracterısticaserealizara(n−1)·n
2veces❀O(n2)
Haciendoelmismoanalisisconinsercionpuedeverselacomplejidadoscila
entreO(n)(mejorcaso)yO(n2)(peorcaso).
66
Otroejemplo:funcionquedeterminasiunamatrizcuadradaessimetrica:
intconstn=10;
typedefintTMatriz[n][n];
boolsimetrica(TMatrizm){
boolb;
inti,j;
b=true;
for(i=1;i<n;i++)
for(j=0;j<i;j++)
b=b&&(m[i][j]==m[j][i]);
returnb;
}
67
Calculemost(x)(siendoxmatrizn×n):
tomamosncomotamanodelosdatos(yaquelamatrizescuadrada).
suponemosqueelcostedelasasignaciones,evaluaciondecondicionesy
accesoavectorestienencosteO(1).AdemasO(1+1)=O(1):la
combinacionsecuencialdeestasinstruccionesesdecomplejidadO(1)
enestecasolaoperacioncaracterısticaesb=b&&(m[i][j]==m[j][i]);que
esdecomplejidadconstanteO(1).
veamoselnumerodevecesqueserepite:
for(i=1;i<n;i++)
for(j=0;j<i;j++)...
t(x)=n−1 �
i=1
i−1 �
j=0
1=n−1 �
i=1
i=n·(n−1)
2≈a·n
2+b·n+c
LacomplejidaddelalgoritmoesO(n2)(t(x)∈O(n
2))
68
enestecasot(x)∈Θ(n2)yporsupuestot(x)∈Ω(n
2),esdecir,parauntamano
delamatriznsuficientementegrande,existealmenosuncasoenelqueel
algoritmoconsumirauntiempodelordenden2.
...¿podrıamosmejorarelalgoritmo?
Observesequesilamatriznoessimetricaencuantoseencuentraalgunpar(i,j)
talquem[i][j]�=m[j][i],elalgoritmopuedeterminardevolviendoelvalorfalse.
69
Otraversiondesimetrica:
boolsimetrica2(TMatrizm){
boolb;
inti,j;
b=true;i=1;
while((i<n)&&b){
j=0;
while((j<i)&&b){
b=m[i][j]==m[j][i];
j++;}
i++;
}
returnb;
}
70
Lasaccionescaracterısticassonlasinstruccionesmasinternas
b=m[i][j]==m[j][i];yj++;
Enelpeorcasoserealizanelmismonumerodevecesqueantes❀O(n2)
Sinembargo,enprincipioespreferiblelasegundaversionporqueenelpeor
casotienelamismacomplejidadquelaprimeray“haycasosenlosquees
maseficiente”(paraestudiarelcasopromedioendetallehabrıaqueconocer
algunaestimaciondelaprobabilidadconquesepresentacadamatriz).
71
Ejemplo:busquedabinaria.
Supongamosvvectorordenadodeenterosdetamanonyeunentero.
//buscaelelto.eentrelasnprimerasposicionesdev
boolbusqBin(intv[],intn,inte){
intini,fin,med;
boolenc;
ini=0;fin=n-1;enc=false;//iniyfindelimitanunsubarray
while((!enc)&&(ini<=fin)){//v[k]<ep.tk<ini
med=(ini+fin)/2;//v[k]>ep.tk>fin
if(e<v[med])fin=med-1;//sieesmenorbuscamosalaizda
elseif(e>v[med])ini=med+1;//siesmayoraladcha
elseenc=true;
}
returnenc;
}
72
Razonamientointuitivo(einformal):
lasoperacionescaracterısticassonlasqueseejecutandentrodelbucle,que
tienencosteconstanteO(1)
tamanodelproblema=dimensiondelarray(inicialmenten=fin−ini+1)
casopeor:enoestaenelarray❀elbucleseejecutahastaqueini>fin
enlaprimeravueltadelbuclelabusquedasereduceaunsubarraydela
mitaddetamanon/2(divisionentera)
enlasegundavueltaelsubarrayquedaradetamanon/4...
enlavueltak-esimaeltamanodelsubarrayseran/2k
¿cuantasvueltassenecesitanparaterminar?
hastaqueelsubarraysea“vacıo”,esdecir,tengadimension0
Entoncesbuscamoselmenork∈INtalquen/2k<1(divisionentera).
Despejandotenemosk>log2(n).Entoncesserak=[log2(n)]+1(dandoun
numerodevueltasdelordendelog2(n)acabaelbucle).
Luego,lacomplejidadesO(log2(n))=O(log(n))73
¿ysihacemosbusqueda“trinaria”?❀partiren3envezde2
boolbusqTrin(intv[],intN,inte){
intini,fin,t1,t2;
boolenc;
ini=0;fin=N-1;enc=false;
while((!enc)&&(ini<=fin)){
t1=(2*ini+fin)/3;
if(e<v[t1])fin=t1-1;
elseif(e>v[t1]){
t2=(ini+2*fin)/3;
if(e<v[t2]){ini=t1+1;fin=t2-1;}
elseif(e>v[t2])ini=t2+1;
elseenc=true;
}
elseenc=true;
}
returnenc;
}
tendrıamosO(log3(n))=O(log2(n))=O(log(n))
74
Multiplicaciondenumerossinutilizarlapredefinida“*”
Idea:x∗y=x+x+...+x����
yveces
intmultiplica1(intx,inty){
intp=0;
while(y>0){
p=p+x;
y--;
}
returnp;
}
Podemostomarn=ycomotamanodelproblemayelcuerpodelbuclecomo
instruccionescaracterısticas.Esfacilverqueelbucleserepitenveces,porlo
tantot(n)∈O(n)
75
Ideaparamejorarelalgoritmo:porejemplo,multiplicar5por6eslomismoque
multiplicar10(=5∗2)por3(=6/2).Engeneral,multiplicarxpor2yeslo
mismoquemultiplicar2xpory...ysehareducidoeltamanodelprobleman=y
alamitadcondosinstruccionessimples(O(1))!!!
intmultiplica2(intx,inty){
intp=0;
while(y>0){
if((y%2)==0){x=x+x;y=y/2;}
else{p=p+x;y--;}
}
returnp;
}
76
¿Quecomplejidadtendraestanuevaversion?
Eltamanodelprobleman=ysereducealamitadenalgunasiteraciones
(cuandoyespar)yenotrassedecrementaenunaunidad(cuandoesimpar)....
pero,dehechocuandoyesimparloqueocurreesquesereduceen1enla
primeraiteracionyalamitadenlasiguiente(ademascadaiteraciontienecoste
constante).
Enelpeordeloscasosparareducireltamanodelproblemaalamitad
necesitamosdositeracionesconsecutivasdelbucle(cadaunadetiempo
constante).Deestemodoeltamanodelproblemairıatomandolosvaloresn,
n/2,n/4,...,n/2k,...,1.
Analogoalabusquedabinaria...¿tendremostambienenestecaso
t(n)∈O(log(n))?
77
Formalizandolasideasanteriores:
Sinespareltiempodeejecucioneselcorrespondienteaunavueltadel
bucle(detiempoconstante)+eltiempodeejecuciondeunproblemade
tamanon/2:
t(n)=1+t(n/2)
Sinesimpareltiempodeejecucionvienedadoporelinvertidoendardos
vueltasalbucle(detiempoconstante)+eltiempodeejecuciondeun
problemadetamano(n−1)/2queeslomismoquen/2(divisionentera):
t(n)=2+t(n/2)
Entoncest(n)≤2+t(n/2)conindependenciadelaparidadden,luego:
t(n)≤2+t(n/2)≤2+2+t(n/4)≤2+2+...+2����
k
=2k
siendokelmenornaturaltalquen/2k
=0donde/representaenestecaso
divisionentera⇒2k>n⇒k>log2(n).Podemostomark=[log2(n)]+1
Luegot(n)≤2·(log2(n)+1)⇒t(n)∈O(log(n))78
Algoritmosrecursivos
79
Larecursionaparecedeformanaturalenprogramacion,tantoenla
definiciondetiposdedatos(comoveremosentemasposteriores)comoenel
disenodealgoritmos.
Haylenguajes(funcionalesylogicos)enlosquenohayiteracion(nohay
bucles),solohayrecursion.Ennuestrocaso,enC++tenemoslaopcionde
elegirentreiteracionyrecursion.
Treselementosbasicosenlarecursion:
Autoinvocacion:elprocesosellamaasımismo.
Combinacion:losresultadosdelallamadaprecedentesonutilizadospara
obtenerunasolucion,posiblementecombinadosconotrosdatos.
Casodirecto:elprocesodeautoinvocacioneventualmentealcanzauna
soluciondirecta(sininvocarseasımismo)alproblema.
Intuitivamente:elprocesoseinvocaasımismocondatoscadavezmassimples
hastaquesontansimplesquelasolucionesinmediata.
80
Ejemplo:factorial
intfactorial(intn){//Pre:n>=0
intr;
if(n==0)r=1;
elser=n*factorial(n-1);//(n>0)
returnr;//Post:r=n!
}
Autoinvocacion:lafuncionfactorialseinvocaasımisma
Combinacion:lasolucionaunallamadafactorial(n)(n>0)seobtiene
multiplicandoeldatonporelresultadodelallamadarecursiva
Casodirecto:n=0
81
¿Comoseejecutafactorial(3)?
factorial(3)
3*factorial(2)
2*factorial(1)
1*factorial(0)
1
1
1
2
6
6
82
¿Queocurreenmemoria?
prog ppalfactorial(2)factorial(1)
.....
..........
.....
.....
...............
..... .....
mmmmm
factorial(m)
33333
n
r
nnn
n’
rrr
n’’
n’’’
n’ n’
r’r’r’
r’’
r’’’
factorial(0)
3333
222
1 1
0
n’’
r’’
de activacionRegistros
83
prog ppalfactorial(2)factorial(1)
.....
..........
.....
.....
...............
..... .....
mmmmm
factorial(m)
33333
n
r
nnn
n’
rrr
n’’
n’’’
n’ n’
r’r’r’
r’’
r’’’
factorial(0)
3333
222
1 1
0
n’’
r’’
1
1
2
6
84
Recursionsimple(olineal)
Cadacasorecursivorealizaexactamenteunallamadarecursiva.Elnumerodellamadas
recursivasdependelinealmentedeltamanodelosdatos.Esquema(procedimental):
void<nombreProc>(τxx����
entrada
,τy&y����
salida
){
τxx1;τyy1;...//variableslocales
if(d(x))//d(x)≡xcasodirecto
y=g(x);//g(x)≡solucionalcasodirecto
else{//if(¬(d(x)))
x1=s(x);//s(x)≡funcionsucesor:descomposiciondedatos
<nombreProc>(x1,y1);//llamadarecursiva
y=c(x,y1);//c(x,y1)≡funciondecombinacion
}
}
85
Lafuncionfactorialseajustaaesteesquema.Vistacomoprocedimiento:
voidfactorial(intn,int&r){//Pre:n>=0
intn1,r1;
if(n==0)r=1;
else{//(n>0)
n1=n-1;
factorial(n1,r1);
r=n*r1;//Post:r=n!
}
}
Casodirecto:d(n)=(n==0)
Resultadodelcasodirecto:g(n)=1
Funcionsucesor:s(n)=n−1
Funciondecombinacion:c(n,r1)=n∗r1
86
Ejemplo:multiplicacionporelmetododelcampesinoegipcio.
voidmultiplica(intn,intm,int&r){//Pre:n>=0,m>=0
intn1,m1,r1;
if(m==0)r=0;
elseif(m==1)r=n;
elseif((m%2)==0){//m>1ypar
n1=n+n;m1=m/2;
multiplica(n1,m1,r1);
r=r1;
}
else{//m>1eimpar
n1=n+n;m1=m/2;
multiplica(n1,m1,r1);
r=n+r1;
}
}//Post:r=n*m
87
Seajustaalesquemaderecursionsimple:
Casodirecto:d(n,m����
x
)=(m==0)∨(m==1)
Resultadodelcasodirecto:g(n,m����
x
)=
0sim=0nsim=1(⊥e.o.c.)
Funcionsucesoryfunciondecombinacion:aparentementehaydosllamadas
recursivas,peroesfacilobservarquesoloserealizaraunadeellasporque
tienencondicionesexcluyentes(yexhaustivas).Tenemos:
s(n,m����
x
)=(2∗n,m/2)c(n,m����
x
,r1 ����
y1
)=
�
r1simesparr1+nsimesimpar
88
Elesquemaderecursionsimplepuedeampliarseconsiderandovarioscasos
directosytambienvariasdescomposicionesparaelcasorecursivo.Loimportante
esquelasalternativasseanexhaustivasyexcluyentes,yqueencadacasosolose
ejecuteunallamadarecursiva.
if(d1(x))y=g1(x);
...
elseif(dn(x))y=gn(x);
elseif(r1(x)){x1=s1(x);<nombreProc>(x1,y1);y=c1(x,y1);}
...
elseif(rm(x)){xm=sm(x);<nombreProc>(xm,y1);y=cm(x,y1);}
else{xm+1=sm+1(x);<nombreProc>(xm+1,y1);y=cm+1(x,y1);}
Asıenelejemplodelamultiplicaciontendrıamos:
Casosdirectos:d1(n,m)=(m==0)yd2(n,m)=(m==1)
Resultadosdeloscasosdirectos:g1(n,m)=0yg2(n,m)=n
Funcionesdeselecciondelcasorecursivo:r1(n,m)=((m%2)==0)
Funcionesdedescomposicion:s1(n,m)=s2(n,m)=(2∗n,m/2)
Funcionesdecombinacion:c1(n,m,r1)=r1yc2(n,m,r1)=r1+n89
Recursionfinalodecola
Casoespecialdelarecursionsimpledondelafunciondecombinacionse
limitaatransmitirelresultadodelallamadarecursiva,esdecir,c(x,y1)=y1❀puedereemplazarsey1poryenlallamadarecursivayası:
•Lallamadarecursivaesloultimoquesehace(poresosellamafinal)
•Elresultadoesobtenidodealgunodeloscasosdirectos.
Ejemplo:algoritmodeEuclides:
voidmcd(intn,intm,int&r){//Pre:n,m>=0
intr1,t;
//casodirecto:d(n,m)=(m==0);
if(m==0)r=n;//resultadoc.d.:g(n,0)=n
else{//m>0
t=m;m=n%m;n=t;//s(n,m)=(m,n%m)
mcd(n,m,r1);//llamadarecursiva
r=r1;//c(n,m,r1)=r1
}
}//Post:r=mcd(n,m)90
Trazadeunaejecucionparalallamadamcd(12,20)
nodellamadanm
11220
22012
3128
484
540
Notesequelafunciondecombinacionselimitaadevolverelresultadodela
llamadarecursiva.Podemosrehacerelcodigo:
mcd(n,m,r1);r=r1;
�
❀mcd(n,m,r);
conloquetenemosrecursionfinal:lallamadaesloultimoquesehaceyel
resultadosaldradealguncasobasico.
Larecursionfinalpuedetransformarsefacilyeficientementeeniteracion.91
Recursionmultiple
Almenosuncasorecursivorealizamasunallamadarecursiva.Esquema:
void<nombreProc>(τxx����
entrada
,τy&y����
salida
){
τxx1,...,xk;τyy1,...,yk;...//variableslocales
if(d(x))//d(x)≡xescasodirecto
y=g(x);//g(x)≡solucionalcasodirecto
else{//if(¬(d(x)))
x1=s1(x);//s1(x)❀descomposiciondedatos
<nombreProc>(x1,y1);//llamadarecursiva1
x2=s2(x);//s2(x)❀descomposiciondedatos
<nombreProc>(x2,y2);//llamadarecursiva2...xk=sk(x);//sk(x)❀descomposiciondedatos
<nombreProc>(xk,yk);//llamadarecursivak
y=c(x,y1,...,yk);//c(...)≡funciondecombinacion
}
}92
Ejemplo:numerosdeFibonacci
voidfib(intn,int&r){//Pre:n>=0
intn1,n2;intr1,r2;
if(n==0||n==1)r=1;
else{
n1=n-1;
fib(n1,r1);
n2=n-2;
fib(n2,r2);
r=r1+r2;
}//Post:r=fib(n)
}
casosdirectos:d(n)=(n==0)∨(n==1);g(0)=g(1)=1
funcionessucesor:s1(n)=n−1;s2(n)=n−2
funciondecombinacion:c(n,r1,r2)=r1+r2
Comoanteselesquemaesgeneralizableconvarioscasosdirectosyvarios
recursivos.93
Hemosaplicadodirectamenteladefinicionsiguiente:
fib(n)=
1sin=0on=1
fib(n−2)+fib(n−1)e.o.c
fib(4)
fib(2)fib(3)
fib(0)fib(1)fib(1)fib(2)
fib(0)fib(1)1 1
1+1=2 1
2+1=3
1 1
1+1=2
2+3=5
Observacion:estecomputorepiteevaluaciones(p.e.fib(2)seevalua2veces).
94
Resumendeideas:Clasificaciondelostiposderecursividad:
SIMPLE(exactamenteunallamadarecursivaencadacasorecursivo)
•FINAL(norequierecombinacionderesultados)
•NOFINAL(requierecombinacionderesultados)
MULTIPLE(masdeunallamadarecursivaenalgunodeloscasosrecursivos)
95
Disenodealgoritmosrecursivos
Metodologıadeldisenodealgoritmosrecursivos:
Buscarunplanteamientorecursivodelproblema(describirlasoluciondel
mismoenformarecursiva).
Hacerunanalisisdecasosparadeterminarloscasosdirectosdi(x)yloscasos
recursivosrj(x)demodoquelasalternativasseanexhaustivasymutuamente
excluyentes(deacuerdoconelesquemapropuestolaexclusionestagarantizadaen
elcodigo).
Determinarlassolucionesparaloscasosdirectosgi(x)yladescomposicion
recursivasj(x).
•Ladescomposicionrecursivadebepermitirhacerlasllamadasrecursivas,i.e.,
quetienensentidolasllamadas<nombreProc>(si(x),yi);
•Funciondeacotacionyterminacion(compl):lasfuncionessucesordeben
garantizarlaterminaciondelarecursion:“lacomplejidaddelproblemadebe
reducirseencadallamadarecursiva”:compl(si(x))<compl(x)
Definirlasfuncionesdecombinacionci(x,yi)96
Funcionesdeacotacionyterminacion
Enfactorialpodemosdefinircompl(n)=n(paraelcasodirectotenemos
compl(0)=0)ycomos(n)=n−1,tenemoscompl(s(n))<compl(n)
Enmultiplicadefinimoscompl(n,m)=m(paraloscasosdirectos
compl(n,0)=0ycompl(n,1)=1)ycomos(n,m)=(2∗n,m/2)tenemos
compl(s(n,m))=compl(2∗n,m/2)=m/2<m=compl(n,m)
Enfibdefinimoscompl(n)=n(paraloscasosdirectoscompl(0)=0y
compl(1)=1);tenemoss1(n)=n−1ys2(n)=n−2.Entonces
compl(s1(n))=compl(n−1)=n−1<n=compl(n)y
compl(s2(n))=compl(n−2)=n−2<n=compl(n).
Enestecasoesinteresanteobservarqueladescomposicionrecursivapermite
hacerlasllamadasrecursivas:
(Pre:n≥0)∧¬(d(n))⇒s1(n)≥0,s2(n)≥0
¿Quefunciondeacotacionpodemostomarparamcd?.Notesequelallamada
mcd(12,20)producelallamadarecursivamcd(20,12)...enquesentido
disminuyelacomplejidad?97
Idea:elalgoritmoprimeroordenaelpar(n,m)demodoquen>mylafuncion
sucesorhaces(n,m)=(m,n%m)...entonceselsegundoelementodelparsiempre
disminuyedetamano!!(esfacilverquen%m<m).
Definimoscompl(n,m)=mytenemos:
compl(s(n,m))=compl(m,n%m)=n%m<m=compl(n,m)
(elcasodirectoescuandom=0yporloqueacabamosdevereventualmentese
alcanzaraunpardelaforma(n,0))
98
Ejemplo:disenodeunafuncionrecursivaquecalcule�n
i=02i:
buscamosunprocedimientosumaDoble(n,r)querecibancomoentraday
calculer=�n
i=02i.Planteamientorecursivo�n
i=02i=�n−1
i=02i+2n❀la
llamadarecursivaseharaconentradan−1
analisisdecasos:
•casodirecto:d(n)=(n==0);g(n)=0
•casorecursivo(n>0):
◦descomposicionrecursiva:s(n)=n−1.Permitehacerlallamada
sumaDoble(s(n),r1)ydefiniendocompl(n)=ntenemosterminacion
asegurada)
◦funciondecombinacion:c(n,r1)=r1+2n
99
Contodoellolaimplementacionresultasencilla(ysegura):
voidsumaDoble(intn,int&r){//Pre:n>=0
intn1,r1;
if(n==0)r=0;
else{
n1=n-1;
sumaDoble(n1,r1);
r=r1+2*n;
}
}//Post:r=sum(i=0..n)2*i
Naturalmenteestecodigosepuedemejorar:
intsumaDoble(intn){
if(n==0)return0;
elsereturn(2*n+sumaDoble(n-1));
}
100
Busquedabinariarecursiva:dadounvectordeenterosvordenadodemenora
mayor-puedecontenerrepeticiones-yunenteroe,decidirsieapareceenv.
Idea:calcularlaposicionmediamdelvectorv;comparareconelelemento
dedichaposicionv[m]:sie<v[m]buscarenlamitadizquierda;sie>v[m]
buscarenlamitadderecha;ysie=v[m],entoncesyalohemosencontradoy
acabaelproceso.
Elplanteamientorecursivoparececlaro.Elprototiposerıa:
voidbuscaBin(intv[],intn,inte,bool&esta)
...¿queaspectotendrıaunallamadarecursiva?,esdecir,¿comoseindicala
busquedaenlamitadizda.oenladecha.?.
Hayquedelimitarenvelsubarraydondeseharalabusqueda❀ındicesini
yfin,quemarcanelinicioyelfinaldedichosubarray.Generalizamosel
procedimientodelmodosiguiente:
voidbuscaBin(intv[],intn,inte,intini,intfin,bool&esta)
buscaeleltoeenelsubarraydevdelimitadoporiniyfin;devuelveenestael
resultadodelabusqueda.101
Analisisdecasos:alavistadelplanteamientoanterior,simeslaposicion
mediahaytrescasos:
•e<v[m]:buscaralaizda.,esdecir,entreiniym−1(noseincluyela
posicionmenlasiguientebusqueda).
•e>v[m]:buscaraladcha.,entrem+1yfin(mquedaexcluido).
•e=v[m]:acabalabusqueda
Losındicesiniyfinvanaproximandoseencadallamadahastaque:
•seencuentraelelto:e=v[m],obien,
•iniyfinse“cruzan”(ini>fin):p.e.sie=18,ini=7yfin=8y
tenemos:
6
...
7
17
8
36
9
...
seram=7,enlasiguientevuelta:ini=fin=8.Yenlasiguienteini=8
yfin=7:sehancruzado.
102
Tenemosdoscasosbasicos(asumimos:med=(ini+fin)/2)
•d1(v,n,e,ini,fin)=(v[med]==e),g1(v,n,e,ini,fin)=true
•d2(v,n,e,ini,fin)=(ini>fin),g2(v,n,e,ini,fin)=false
Casosrecursivos(sedaporsentadov[med]!=eyini≤fin):
•r1(v,n,e,ini,fin)=(e<v[med]),s1(v,n,e,ini,fin)=(v,n,e,ini,med−1).
LlamadarecursivabuscaBin(v,n,e,ini,med-1,r).Funciondecombinacion
c1(v,n,e,ini,fin,r)=r
•r2(v,n,e,ini,fin)=(e>v[med]),s2(v,n,e,ini,fin)=(v,n,e,med+1,fin).
LlamadarecursivabuscaBin(v,n,e,med+1,fin,r).Funciondecombinacion
c2(v,n,e,ini,fin,r)=r
Alavistadelasfuncionesdecombinacion,elprocedimientoadmiterecursion
final.Notesequelasllamadasrecursivasefectivamentepuedenrealizarse.
103
Funciondeacotacionyterminacion:podemosdefinir
compl(v,n,e,ini,fin)=fin−ini+1ytenemos:
•compl(s1(v,n,e,ini,fin))=comp(v,n,e,ini,med−1)=med−1−ini+1=
med−ini≤����
med≤fin
fin−ini<fin−ini+1=compl(v,n,e,ini,fin)
•compl(s2(v,n,e,ini,fin))=comp(v,n,e,med+1,fin)=fin−(med+1)+1=
fin−med≤����
ini≤med
fin−ini<fin−ini+1=compl(v,n,e,ini,fin)
104
Finalmenteelcodigopodrıaquedardeestemodo:
voidbuscaBin(intv[],intn,inte,intini,intfin,bool&esta){
intmed;
if(ini>fin)esta=false;
else{
med=(ini+fin)/2;
if(e<v[med])buscaBin(v,n,e,ini,med-1,esta);
elseif(e>v[med])buscaBin(v,n,e,med+1,fin,esta);
elseesta=true;
}
}
esfaciltransformarloenunafuncionquedevuelvaciertoofalso.
C++admitesobrecargadefuncionesysepodrıaimplementarunafuncion
delmismonombrequesolorecibaelvector,eltamanoyelelementoabuscar:
boolbuscaBin(intv[],intn,inte){
returnbuscaBin(v,n,e,0,n-1);
}105
Ecuacionesrecurrentes
lacomplejidaddemuchosalgoritmosrecursivosynorecursivos(vease
ejemplodemultiplicaciondelapag.76)vieneexpresadaamenudomediante
ecuacionesrecurrentes,esdecir,lafunciont(n)esrecursiva(apareceensu
mismadefinicion).
Ejemplos:
Factorialcomoprocedimiento(pg.86):
•casodirecto:condicion+asignacion❀constante
•rec:condicion+resta+asignacion+t(n−1)+multiplicacion+asignacion❀
constante+t(n−1)
t(n)=
�
1sin=01+t(n−1)e.o.c.
Multiplicacion(pag.87):t(m)=
�
1sim=0om=11+t(m/2)e.o.c.
Fibonacci(pag.93):t(n)=
�
1sin=0on=11+t(n−1)+t(n−2)e.o.c.
106
Desplieguederecurrencias
Hemosexpresadot(n)comoecuacionrecursiva,peronecesitamosunaformulano
recurrenteparadeterminarelordendecomplejidad.Estaformulanoessiempre
sencilladeobtener,peroenmuchoscasospuedeprocedersepordesplegado:
desplegarlarecurrencia,i.e.,reemplazart(n)enlaecuacionporsuvalor,las
vecesqueseanecesariohastaencontrarunaformuladependientedelnumero
kdellamadasrecursivas.Determinandoelvalordekquepermitealcanzar
uncasodirectoseobtieneunaformulanorecursivaparat(n).
enalgunoscasoslaobtenciondelaformulaexactanoesevidenteypara
demostrarlacorrecciondelamismapuedesernecesariohaceruna
demostracionporinduccion.
paraobtenercotassuperiores,i.e.,paraprobart(n)∈O(f(n))podemos
acotarsuperiormentet(n)confuncionesmascomodasdemanejar.
107
Ejemplos:
paraelfactorialtenemos:
t(n)=1+t(n−1)=1+1+t(n−2)=1+1+1+t(n−3)=k+t(n−k)
Paraalcanzarelcasodirecto,debeserk=n,luego
t(n)=n+t(0)=n+1❀t(n)∈O(n)
paralamultiplicacion(/divisionentera):
t(m)=1+t(m/2)=1+1+t(m/4)=1+1+1+t(m/23)=k+t(m/2
k)
Elcasodirectosealcanzacuandom/2k
=1,i.e.,k=log2(m).Luego
t(m)=log2(m)+t(1)=log2(m)+1∈O(log(m))
parafibonacci,desplegando:
t(n)=1+t(n−1)+t(n−2)=1+1+t(n−2)+t(n−3)+1+t(n−3)+t(n−4)=
3+t(n−2)+2·t(n−3)+t(n−4)=...
noobtenemosunaformulasencillaparalaecuacionexplıcita.Peroqueremos
acotar...utilizamoselhechot(n−2)≤t(n−1);entoncesparalaecuacionde
recurrenciaobtenemost(n)≤1+2·t(n−1).
108
Despleguemosahora:
t(n)≤1+2·t(n−1)≤3+4·t(n−2)≤7+23·t(n−3)≤15+2
4·t(n−4)≤...
¿...≤2k−1+2
k·t(n−k)?
Probemosquet(n)≤2k−1+2
k·t(n−k)parak>0:
k=1:t(n)≤1+2·t(n−1)(acotacioninicial)
k⇒k+1:
t(n)≤2k−1+2
k·t(n−k)(porh.i)
≤2k−1+2
k(1+2·t(n−k−1))(poracotacioninicial)
=2k+1
−1+2k+1
·t(n−(k+1))qed
Yatenemosprobadalaacotaciont(n)≤2k−1+2
k·t(n−k)yparaalcanzarel
primercasobasiconecesitamosn−k=1,i.e.,k=n−1.Enesecasotenemos
t(n)≤2n−1
−1+2n−1
·t(1)=2n−1,luegot(n)∈O(2
n).
...ordendecomplejidadmuyalto!,seraporquenuestraacotacionesmala?
Puededemostrarset(n)∈Θ(φn)(Brassard&Bratley),siendoφ=1,618...(razon
aurea!)❀nuestraacotacionnoes“tan”mala...elalgoritmoutilizadosıesmuymalo!!!109
Resoluciongeneralderecurrencias
(Bibliografıa:RicardoPena)
Mediantelatecnicadedesplegadopuedendemostrarsealgunosresultados
generalessobrerecurrenciasycomplejidad.
Disminuciondeltamanodelproblemaporsustraccion
t(n)=
c0si0≤n<n0
a·t(n−b)+c·nk
sin≥n0
⇒t(n)∈
Θ(nk+1
)sia=1
Θ(andivb
)sia>1
c0:costedelcasodirecto
a≥1:numerodellamadasrecursivas
n−b:tamanodelossubproblemasgenerados(b≥1)
c·nk:costedelapreparaciondellamadas(funcionessucesor)ycombinacion
delosresultados(funcionesdecombinacion)
Unejemplosencillodeestecasoeselfactorial.
110
Disminuciondeltamanodelproblemapordivision
t(n)=
c0si0≤n<n0
a·t(n/b)+c·nk
sin≥n0
⇒t(n)∈
Θ(nk)sia<b
k
Θ(nk·log(n))sia=b
k
Θ(nlogb(a)
)sia>bk
c0:costedelcasodirecto
a≥1:numerodellamadasrecursivas
n/b:tamanodelossubproblemasgenerados(b≥1).
c·nk:costedelapreparaciondellamadas(funcionessucesor)ycombinacion
delosresultados(funcionesdecombinacion)
Ejemplo:busquedabinaria(pag101).Tamanom:dimensiondelsubarray
(fin−ini+1)
t(m)=
1sim=0
t(m/2)+1e.o.c
Tenemosa=1,b=2,k=0,luegot(n)∈Θ(log(n))111
Lasformulasanteriorespuedenresolvermuchosdeloscasosquesenos
presentan,peroengeneral,elanalisisdecomplejidadrequiereunadosisde
ingenioeimaginacion.
¿QuecomplejidadtieneelalgoritmodeEuclides(pag.90)?.Ideaintuitiva:
sin<menunpasomcd(n,m)❀mcd(m,n)ydespessiempreelprimer
argumentoesmayorqueelsegundo
sepruebaquen%m<n2(trescasos:m>
n2,m<
n2,m=
n2)
endosllamadasrecursivastenemos:
mcd(n,m)❀mcd(m,n%m)❀mcd(n%m,m%(n%m))
ambosargumentossehanreducidoalamitad(comopoco)endospasos,i.e.,
n%m<n2ym%(n%m)<
m2.
elalgoritmoterminacuandom=0...eltiempodeejecucionestaraacotado
por1+2∗log2(min{n,m}),luegosucomplejidadestaenO(log(min{n,m}))
Notesequeestealgoritmoeshiper-sensiblealosdatosdeentrada:p.e.
mcd(1000000000,999999999)solorequieretresllamadasamcd.112
Algoritmosavanzadosdeordenacion
Ordenacionpormezcla(mergesort)yordenacionrapidadeHoare(quicksort).
Ambosutilizanunaestrategiadivideyvenceras:separteelarrayendospartes
queseordenan(recursivamente)porseparado.
OrdenacionrapidadeHoare
Idea(planteamientorecursivo):
eligirunelementocualquieradelarraycomopivote(porejemplo,elprimero);
particionarelarrayendossubarrays,unoconloselementosquesonmenores
(oiguales)queelpivoteyotroconlosquesonmayores(elpivotequedaenel
centro,separandoambossubarrays)
ordenarrecursivamenteambaspartes.
113
5512429461867 v
pivote
1261855429467
6121842556794
6121842556794
pivote
menoresmayores
ordenacion recursiva
ordenacion recursiva
40
40
Ademaselquicksortescapazdehacertodoelprocesosobreelpropioarrayde
entrada(sinarraysauxiliares).
114
Igualqueenlabusquedabinaria,paradelimitarlossubarraysaordenarenlas
llamadasrecursivas,utilizamosdosındicesiniyfin.Ası,lacabeceradel
procedimientotendraelaspectoquicksort(intv[],intini,intfin)
analisisdecasos:
•casodirecto:ini≥fin;elsubarrayestavacıootieneunsoloelemento,no
haynadaquehacerenv
•casorecursivo(ini<fin):considerarcomopivotepiv=v[ini]yreordenar
(parcialmente)elsubarrayv[ini..fin]demodoquepivquedeensu
posicionfinalp,dejandoalaizdalosmenoresoigualesyaladerechalos
mayores
•ordenarrecursivamentelossubarraysv[ini..p−1]yv[p+1..fin](recursion
multiple)
Funciondeacotacion:compl(v,ini,fin)=fin−ini+1(tamanodel
subvector,comoenlabusquedabinaria).
115
Implementacion:
voidquickSort(intv[],intini,intfin){
intp;
if(ini<fin){
particion(v,ini,fin,p);
quickSort(v,ini,p-1);
quickSort(v,p+1,fin);
}
}
Quedaporimplementarelprocedimientodeparticion(v,ini,fin,p)quereorganice
loselementosdev[ini..fin]
inifin p
v
<= v[p]> v[p]
116
Funcionamientodeparticion:
definimospiv=v[ini],
inf=ini+1,sup=fin:elındiceinfavanzahacialaderechaysup
retrocedehacialaizquierdahastaquesecrucen:
•infavanzamientrasv[inf]<=piv
•supretrocedemientrasv[sup]>piv
•seintercambianlosvaloresdev[inf]yv[sup]
•serepiteelproceso
elpivotepivsecolocaensusitiointercambiandoloconelelementodev[sup]
yp=sup(posiciondondehaquedadoelpivote).
117
voidparticion(intv[],intini,intfin,int&p){
intinf,sup,piv,tmp;//ini<fin(loexigeqs)
piv=v[ini];
inf=ini+1;sup=fin;//inf<=sup+1
while(inf<=sup){//v[ini+1..inf-1]<=piv,v[sup+1..fin]>piv
while((inf<=sup)&&(v[inf]<=piv))inf++;
while((inf<=sup)&&(v[sup]>piv))sup--;
if(inf<sup){tmp=v[inf];v[inf]=v[sup];v[sup]=tmp;inf++;sup--;}
}
v[ini]=v[sup];v[sup]=piv;
p=sup;
}
118
Analisisdecomplejidaddelaordenacionrapida
(elanalisisformaldeestealgoritmoescomplicado)
elpeorcasoparaelquicksortesunarrayordenadoyaquedalugara
particionesmuydesiguales...¿porque?
lacomplejidaddeparticionsobreunarraydekcomponentesesO(k).Enel
peorcasolaparticiondalugaraunarrayde0componentesyotrodek−1
componentes(maselpivote).
lacomplejidadentoncesresulta�n
k=1O(k)�O(n2)
Enrealidad,enelpeorcaso,funcionaesencialmentecomolaordenacionpor
seleccion.Enelmejorcaso(laparticionesequilibrada)lacomplejidades
O(n·log(n))yenelcasomedio(complicadodeestimar)tambienesO(n·log(n)).
notieneuncomportamientonatural:noaprovechaelorden.
estealgoritmoesmuysensiblealaelecciondelpivote(elmejorpivoteserıala
mediana).
119
Ordenacionpormezcla
Idea:separteelvectorendosmitades,seordenanrecursivamenteambasmitades
ysehacelamezclaordenadadelasmismas.Ejemplo:
746913
013 245
mm+1
467139
134679
Ordenacion
recursiva
Ordenacion
recursiva
Mezcla ordenada
120
Planteamientorecursivo:paraordenarelarrayv[ini..fin]
calculamoslaposicionmediamed=(ini+fin)/2yordenamos
recursivamentelossubarraysv[ini..med],v[med+1..fin]
mezclamosordenadamentelossubarraysv[ini..med],v[med+1..fin]
Analisisdecasos:
casodirecto:ini≥fin;elsubarrayestavacıootieneunsoloelemento,no
haynadaquehacerenv
casorecursivo(ini<fin);dosllamadasrecursivas(recursionmultiple):una
paraordenarv[ini..med]yotraparaordenarv[med+1..fin].
Funciondeacotacion:compl(v,n,ini,fin)=fin−ini+1(igualqueenla
busquedabinaria).
121
Implementacion(suponemosimplementadoelprocedimientodemezcla):
voidmergeSort(intv[],intini,intfin){
intmed;
if(ini<fin){
med=(ini+fin)/2;
mergeSort(v,ini,med);
mergeSort(v,med+1,fin);
mezcla(v,ini,med,fin);
}
}
122
Elprocedimientodemezcla:
paraconseguirunaversioneficiente(O(n))senecesitaunarrayauxiliar.El
tamanodeestevectoresfin−ini+1,peronopuedehacerseladeclaracion:
intaux[fin-ini+1]
enelprocedimiento(fineinisonparametrosdelmismo).
unasolucionesdefinirunvectordetamanonyutilizarsolounaparte;
perotambiensepuedecreardinamicamenteunpunteroaunarrayde
enteros,reservandolamemorianecesaria:
int*aux=newint[fin-ini+1];
ElpunteroauxapuntaalprimerelementodelarrayyenC++,debidoala
dualidadpuntero/array,podemostratarauxcomosifueseunarraynormal
defin-ini+1elementos.
Cuidado:alterminarelprocedimientohayqueasegurarsedeliberarel
espacioqueocupa:
delete[]aux;123
ideadelalgoritmodemezcla:
inimedfin
0med−inifin−ini
v
aux
....................
..... .....
i1i2
j
Secopiav[ini..fin]enaux[0..fin−ini]yluegoauxsevarecorriendocondos
ındices,desde0ydesdemed−ini+1,colocandoordenadamentelos
elementosenv.
124
voidmezcla(intv[],intini,intmed,intfin){
int*aux=newint[fin-ini+1];
inti1,i2,j;
for(j=ini;j<=fin;j++)aux[j-ini]=v[j];//copiamosvenaux
i1=0;//i1recorreauxde0amed-ini
i2=med-ini+1;//i2vademed-ini+1afin-ini
j=ini;//jrecorrevdeiniafin
while((i1<=med-ini)&&(i2<=fin-ini)){
if(aux[i1]<=aux[i2]){v[j]=aux[i1];i1++;//eltotomadodeaux[0..med-ini]
}else{v[j]=aux[i2];i2++;}//eltodeaux[med-ini+1..fin-ini]
j++;}//jsiempreavanza
while(i1<=med-ini){//seacabadecopiaraux[0..med-ini]
v[j]=aux[i1];j++;i1++;}
while(i2<=fin-ini){//seacabaaux[med-ini+1..fin-ini]
v[j]=aux[i2];j++;i2++;}
delete[]aux;//eliminaciondeaux
}
125
Analisisdecomplejidaddelaordenacionpormezcla
casomejor=casopeor(losbuclessiempreseejecutan)
paraunarraydedimensionkenmezclasehaceunrecorridoportodaslas
componentes(mediantelostresbucleswhile).Lasoperacionesquesesehacen
enlosbuclessontodasO(1).Portanto,lacomplejidaddemezclaesO(k)
lossubarraysdesucesivasllamadasdemergeSortsondelaforma:n
n/2n/2
n/4n/4n/4n/4
Entotal1mezclaparatamanon,2paratamanon/2,4paratamanon/4...
2k
paratamanon/2k,quetienenuncostetotalde
n+2n2+2
2n22+...+2
kn2k=n+...+n
����
kveces
siendon2k=1,i.e.,k=log2(n),luegotienecomplejidadO(n·log(n)).
126
Formalmentetenemoslarecurrencia:t(n)=
1sin≤1
2·t(n/2)+ne.o.c.
Porlasformulasgeneralesderesolucionderecurrencias(pag.111),con
a=2,b=2,k=1tenemosdirectamentet(n)∈O(n·log(n))
Haciendodespliegue“manual”:
t(n)=2·t(n/2)+n=2(2·t(n/4)+n/2)+n=22·t(n/2
2)+2n=...=
¿2k·t(n/2
k)+k·n?
(sedemuestraporinduccion)
Parareducirelproblemaalcasodirectodebeserk≈log2(n)ytenemosentonces:
t(n)=2log2(n)
·t(n/2log2(n)
)+log2(n)·n=n+log2(n)·n
Tenemosentoncest(n)∈O(n·log(n)).Esmas,comonohemosutilizadoacotaciones
tenemost(n)∈Θ(n·log(n))
127
LaordenacionrapidadeHoareylaordenacionpormezclasondos
algoritmosgeneralesysofisticadosdeordenacion
EltiempodeejecuciondeambosenelcasomedioestaenO(n·log(n)),
perolaordenacionpormezclatieneelinconvenientedequenecesitaespacio
adicional(arraysauxiliares),
mientrasquelaordenacionrapidaoperasobreelarraydeentrada.
...¿comodeeficientementesepuedenordenararrays?,o¿cualeslacomplejidad
mınimaquepuedetenerunalgoritmodeordenacionenelcasopeor?,¿es
mejorablelacotaO(n·log(n))delaordenacionpormezcla?.Buscamosunacota
inferiorΩ(f(n))paralosalgoritmosdeordenacion.
Basicamenteparaordenarsehacendostiposdeoperaciones:comparaciones
eintercambios.
elnumerodeintercambiosesmenoroigualqueelnumerodecomparaciones
lacomplejedaddeunalgoritmodeordenacionbasadoencomparaciones
estadeterminadaporelnumerodeestas.128
Arbolesdedecision
Paraordenartreselementose1,e2ye3,tenemoselsiguientearboldedecision:
e1 e3 e2
e1 e2 e3
e1<=e3
e2 e1 e3 e1<=e3
e3 e1 e2
e2<=e3
e2 e3 e1e3 e2 e1
SI
SISI
SI SI
NO
NO
NO NO
NO
e1<=e2
e2<=e3
Tenemos3!=6posiblesordenaciones;elpeorcasounmınimodetres
comparaciones.
129
Paraunarraynelementos,¿cuantascomparacionesnecesitaremosenelpeor
caso?❀profundidaddelarboldedecision.
Prop:unarbolbinariodeprofundidadptienealosumo2phojas.
nuestroarboldedecisiontieneexactamenten!hojas(todaslasposibles
ordenaciones)
laprofundidadpdenuestroarboldedecisiondebesertalque2p≥n!(paraque
puedacontenerlasn!hojas)
luegodebeserp≥log2(n!),conloquet(n)∈Ω(log(n!))
porotrolado,sepuedeprobarn!≥(n/2)n/2
,ydeaquıt(n)∈Ω(n·log(n))
Enconclusion,cualquieralgoritmodeordenacionbasadoen
comparacionesrequiereuntiempoΩ(n·log(n))paraordenarunarray
denelementos
Laordenacionpormezclaigualaestacota,perorequierearraysauxiliares...
¿existiraunalgoritmoqueigualelacotaynoutilicearraysadicionales?
...continuara130