Professional Documents
Culture Documents
Asidai 225x c06 Ud2
Asidai 225x c06 Ud2
Arbres
Isidre Guix Miranda
Recursivitat. Arbres
ndex
Introducci ............................................................................................... Objectius ................................................................................................... 1. Recursivitat ......................................................................................... 1.1. Definici i exemples de recursivitat .......................................... 1.1.1. Clcul del factorial dun nombre natural ....................... 1.1.2. Clcul dun nombre de la srie de Fibonacci ................. 1.1.3. Clcul del capital amb inters compost ......................... 1.2. Recursivitat i piles ...................................................................... 1.2.1. Funcionament intern de la recursivitat ......................... 1.2.2. Simulaci de la recursivitat amb piles ........................... 1.3. Aplicacions clssiques de recursivitat ....................................... 1.3.1. El problema de les torres de Hanoi ................................ 1.3.2. El mtode dordenaci rpida ......................................... 2. Arbres .................................................................................................. 2.1. Arbres binaris .............................................................................. 2.1.1. Implementaci darbres binaris ...................................... 2.1.2. Algorismes de tractament en arbres binaris ................. 2.2. Arbres binaris de recerca ............................................................ 2.2.1. Algorisme de recerca ........................................................ 2.2.2. Algorisme dinserci ......................................................... 2.2.3. Algorisme deliminaci .................................................... 2.3. Arbres balancejats ....................................................................... 2.3.1. Algorisme dinserci ......................................................... 2.3.2. Algorisme deliminaci ................................................... 2.4. Arbres multicam ......................................................................... 2.4.1. Arbres B ............................................................................. 2.4.2. Arbres B+ .......................................................................... 2.4.3. Utilitat en arxius seqencials indexats ..........................
5 7 9 9 10 13 14 16 16 17 19 19 21 23 24 25 26 27 29 29 30 33 34 36 38 39 46 48
Recursivitat. Arbres
Recursivitat. Arbres
Introducci
En la unitat didctica Dades lineals en memria dinmica ens hem endinsat en la gesti dinmica de la memria i en la seva aplicaci per a la implementaci destructures de dades lineals: llistes, piles i cues. Ens manca, per, la seva aplicaci en els arbres, un tipus de dada no lineal molt utilitzat en informtica. Abans, per, dintroduir-nos en el coneixement dels arbres, ens cal endinsar-nos en laprenentatge de la recursivitat, ats que la implementaci dels arbres necessiten aquesta tcnica de programaci. Aix doncs, en el nucli dactivitat Recursivitat introdum aquesta tcnica de programaci consistent a resoldre un problema en termes de si mateix. El coneixement daquesta tcnica sacostuma a deixar per al final de laprenentatge de la programaci estructurada i modular pels motius segents: per efectuar i implementar dissenys recursius cal ser, primer de tot, un bon programador de dissenys no recursius (iteratius) i, a ms, cal tenir molta intuci per saber definir la recursivitat correctament. El fet que aquesta unitat didctica versi sobre recursivitat i arbres podria fer pensar que els dos temes han danar de la m, i no s el cas. Simplement, la implementaci del tipus de dada arbre necessita les tcniques recursives, per la recursivitat s aplicable tant al tractament del tipus de dada arbre com a moltes altres situacions en les quals els arbres no tenen res a veure. En el nucli dactivitat Arbres sintrodueix aquest tipus de dada, fonamental per a la gesti dels arxius seqencials indexats. El tipus de dada arbre introdueix el concepte destructura de ramificaci entre nodes. En les estructures lineals esttiques i dinmiques un element noms t un nic segent. Amb el tipus de dada arbre sinicia la introducci del concepte de ramificaci entre nodes. Per tant, s una estructura dinmica no lineal molt important, per no s lnica; nhi ha daltres com el graf. Daltra banda, aquest nucli dactivitat dedicat als arbres no pretn ser una bblia sobre els arbres. Aquest tipus de dada s tan important que sha estudiat llargament i, per tant, shan generat molts conceptes. Aqu noms en farem una introducci. Per aconseguir els nostres objectius, heu de reproduir en el vostre ordinador i, si pot ser, en diverses plataformes, tots els exemples incorporats en el text. Per a aix, trobareu tots els fitxers necessaris en la
Recursivitat. Arbres
secci Recursos de contingut. Al web tamb trobareu activitats i exercicis dautoavaluaci. I un consell final: com que lassignaci dinmica de memria i la recursivitat sn tcniques molt potents, ens cal conixer-les i aplicar-les, per tamb sn complexes i, per tant, cal anar amb molt de compte!
Recursivitat. Arbres
Objectius
En acabar la unitat didctica, heu de ser capaos del segent: 1. Distingir quan un problema es pot resoldre informticament amb la utilitzaci de tcniques recursives. 2. Aproximar leficincia dexecuci dels algorismes recursius dissenyats. 3. Avaluar la convenincia dutilitzar un algorisme recursiu o un algorisme iteratiu per al disseny de determinats programes. 4. Efectuar un seguiment acurat de les diferents crides recursives que es produeixen en lexecuci dalgorismes recursius. 5. Identificar diferents estructures darbre i implementar-les en llenguatge C. 6. Dissenyar algorismes eficients de recorregut, inserci, eliminaci i consulta. 7. Aplicar les estructures darbre en la implementaci de sistemes darxius seqencials indexats.
Recursivitat. Arbres
1. Recursivitat
El concepte de recursivitat apareix en moltes activitats de la vida diria, per exemple en una fotografia duna fotografia, en un passads que t miralls als extrems, encarats lun amb laltre, en un programa de televisi on apareix un televisor per on semet el mateix programa... Per a nosaltres ens interessa el concepte de recursivitat dins lmbit de la programaci informtica.
La recursivitat s un concepte que permet definir un objecte (problema o estructura de dades) en termes de si mateix. Un subprograma (acci o funci) s recursiu quan al llarg de la seva execuci efectua alguna crida a si mateix.
En els subprogrames la recursivitat es pot donar de dues maneres diferents: Directa: quan el subprograma es crida directament a si mateix. Indirecta: quan el subprograma crida un altre subprograma i aquest, o algun de ms intern, crida el primer. Davant duna situaci recursiva, ens hem de preguntar quan finalitza. El final dun procs recursiu queda garantit amb lexistncia dun estat bsic.
10
Recursivitat. Arbres
En un subprograma recursiu, direm que estem en un estat bsic quan la soluci al problema ja no es presenta de manera recursiva sin directament. A partir de la definici dun problema que exigeix una soluci informtica, direm que una definici recursiva s vlida si es pot determinar lestat bsic i es garanteix lapropament successiu del problema a lestat bsic esmentat. La recursi s una eina important que permet escriure un codi de manera ms compacta i, en certs casos, de manera ms fcil. Aix no obstant, ha de quedar clar que la recursi no facilita ms rapidesa dexecuci ni tampoc permet estalviar espai de memria. En general, s recomanable utilitzar recursi quan el problema ho exigeix. Si no s aix, ser ms convenient utilitzar eines de carcter repetitiu. ! Laprenentatge de laplicaci de la recursivitat en la programaci informtica passa sempre pel coneixement duns exemples clssics. A vegades s bo plantejar-se una soluci iterativa i avaluar el temps necessari per executar la soluci recursiva i la soluci iterativa.
funci factorial (n: natural) retorna natural s si n==0 /* estat bsic */ llavors retorna 1; /* final de la recursivitat */ sin retorna n*factorial (n-1); /* crida recursiva que assegura lapropament a lestat bsic */ fisi fifunci
11
Recursivitat. Arbres
!!
Trobareu el fitxer u2n1p01.c i la resta darxius necessaris en la secci Recursos de contingut del web daquest crdit, concretament a Codi font en C.
void main() { int n,aux; clrscr(); do { printf ("Introdueixi valor no negatiu per a calcular-ne el factorial: "); aux=scanf("%d",&n); neteja_stdin(); } while (aux==0 || n<0); printf ("\n%d! = %lu\n",n,factorial (n)); }
Alerta en lexecuci daquest programa! Pensem que per a lusuari pot ser normal introduir un valor superior a 12 per calcular-ne el factorial, oi? Si agafeu una calculadora que permeti calcular el factorial dun valor (per exemple la calculadora cientfica de Windows) i calculeu 12! i 13! obtindreu els resultats segents: 12! = 479001600 13! = 6227020800 Observem que el resultat de 13! s superior al mxim valor tractable per un unsigned long en plataforma de 32 bits i el programa anterior ens donaria un valor incorrecte, ja que no hi controlem la superaci dels valors mxims permesos. Si ho volem comprovar, podem reversionar el programa anterior i obtenir el segent:
/* u2n1p02.c */ #include #include #include #include <stdio.h> <conio.h> <limits.h> "verscomp.h"
!!
Trobareu el fitxer u2n1p02.c i la resta darxius necessaris en la secci Recursos de contingut del web daquest crdit, concretament a Codi font en C.
unsigned long factorial (int n) /* La funci retorna ZERO si el valor s no calculable segons els tipus de dades emprats degut al fet que el valor "n" provoca resultats massa grans no tractables. */ { unsigned long result; if (!n) return 1; else { result = factorial (n-1); if (ULONG_MAX/n < result) return 0; else return n * result;
12
Recursivitat. Arbres
} } void main() { int n,aux; unsigned long resultat; clrscr(); printf ("Recordem que el valor mxim per unsigned long s %lu\n",ULONG_MAX); do { printf ("Introdueixi valor no negatiu per a calcular-ne el factorial: "); aux=scanf("%d",&n); neteja_stdin(); } while (aux==0 || n<0); if ((resultat=factorial(n))==0) printf ("El resultat de %d! s massa elevat i no el podem calcular.\n",n); else printf ("\n%d! = %lu\n",n,resultat); }
En aquesta versi podem comprovar que lexecuci de 13! ens informa que no s calculable. Fixem-nos que utilitzem la constant simblic ULONG_MAX, que cont el valor ms gran perms per a tipus unsigned long. Recordem, per, que en plataformes de 32 bits algunes versions de C (gcc, per exemple) incorporen els tipus long long int i unsigned long long int, que permeten valors ms alts. Aix, podem considerar una nova versi del programa:
/* u2n1p03.c */ #include #include #include #include <stdio.h> <conio.h> <limits.h> "verscomp.h"
!!
Trobareu el fitxer u2n1p03.c i la resta darxius necessaris en la secci Recursos de contingut del web daquest crdit, concretament a Codi font en C.
unsigned long long factorial (int n) /* La funci retorna ZERO si el valor s no calculable segons els tipus de dades emprats degut al fet que el valor "n" provoca resultats massa grans no tractables. */ { unsigned long long result; if (!n) return 1; else { result = factorial(n-1); if (ULLONG_MAX/n < result) return 0; else return n * result; } } void main() { int n,aux; unsigned long long resultat; clrscr(); printf ("Recordem que el valor mxim per unsigned long s %lu\n",ULONG_MAX); do { printf ("Introdueixi valor no negatiu per a calcular-ne el factorial: "); aux=scanf("%d",&n); neteja_stdin(); } while (aux==0 || n<0); if ((resultat=factorial(n))==0) printf ("El resultat de %d! s massa elevat i no el podem calcular.\n",n); else printf ("\n%d! = %llu\n",n,resultat); }
13
Recursivitat. Arbres
Per aconseguir la compilaci en gcc del darrer programa cal incloure lopci std=C99 en lordre de compilaci.
El programa en C segent mostra la codificaci de les funcions recursives i iteratives de la funci de Fibonacci i comprova la diferncia de temps dexecuci de les funcions recursives i iteratives.
/* u2n1p04.c */ #include #include #include #include <stdio.h> <conio.h> <time.h> "verscomp.h"
!!
Trobareu el fitxer u2n1p04.c i la resta darxius necessaris en la secci Recursos de contingut del web daquest crdit, concretament a Codi font en C.
unsigned long fibo_recursiu (unsigned long n) { if (n==0) return 0; if (n==1) return 1; return fibo_recursiu(n-1)+fibo_recursiu(n-2); } unsigned long fibo_iteratiu (unsigned int n) { unsigned long r1=0,r2=1,i=2,aux; if (n==0) return 0; if (n==1) return 1; while (i<=n) { aux=r2; r2=r2+r1; r1=aux; i++;} return r2; } void main() { int n,aux; time_t tini,tfin;
14
Recursivitat. Arbres
clrscr(); do { printf ("Introdueixi valor no negatiu per a calcular-ne el fibonnacci: "); aux=scanf("%d",&n); neteja_stdin(); } while (aux==0 || n<0); tini=time(NULL); printf ("Calculant iterativament...\n"); printf ("ITERATIVAMENT: %lu",fibo_iteratiu(n)); tfin=time(NULL); printf (" Segons: %f\n",difftime(tfin,tini)); tini=time(NULL); printf ("Calculant recursivament...\n"); printf ("RECURSIVAMENT: %lu",fibo_recursiu(n)); tfin=time(NULL); printf (" Segons: %f\n",difftime(tfin,tini)); }
Executeu el programa i comproveu, per a valors relativament grans (a partir de 30 o 40), la diferncia significativa de temps. Els valors obtinguts dependran, lgicament, de la velocitat de procs de la mquina on sexecutin.
Sobre aquest capital tornem a efectuar el clcul per obtenir el capital acumulat a la fi del segon any. Per tant, es tracta dun procs recursiu que podem plantejar de dues maneres, les quals queden reflectides en les dues versions en pseudocodi.
funci capital_compost1 (C: real, N: natural, I: real) retorna real s si N==0 /* estat bsic */ llavors retorna C; /* fi de la recursivitat */ sin retorna (1+I/100) * capital_compost1 (C, N-1, I); /* crida recursiva */ fisi fifunci funci capital_compost2 (C: real, N: natural, I: real) retorna real s si N==0 /* estat bsic */ llavors retorna C; /* fi de la recursivitat */ sin retorna capital_compost2 ((1+I/100)*C, N-1, I); /* crida recursiva */ fisi fifunci
15
Recursivitat. Arbres
Vegem un programa en llenguatge C que incorpora les dues modalitats i en comprova lexecuci.
/* u2n1p05.c */ #include #include #include #include <stdio.h> <conio.h> <math.h> "verscomp.h"
!!
Trobareu el fitxer u2n1p05.c i la resta darxius necessaris en la secci Recursos de contingut del web daquest crdit, concretament a Codi font en C.
double arrodonir (double r, unsigned int n) { unsigned int i; for (i=1;i<=n;i++) r=r*10; if (r-floor(r)>=0.5) r = ceil(r); else r = floor (r); for (i=1;i<=n;i++) r=r/10; return r; } double capital_rec1 (double inicial, float interes, unsigned int n, unsigned int dec) { if (n==0) return inicial; return arrodonir((1+inters/100)*capital_rec1(inicial,inters,n-1,dec),dec); } double capital_rec2 (double inicial, float inters, unsigned int n, unsigned int dec) { if (n==0) return inicial; return capital_rec2(arrodonir(inicial*(1+inters/100),dec),inters,n-1,dec); } void main() { int n,dec,aux; double inicial; float interes; clrscr(); do { printf ("Capital inicial (no negatiu): "); aux=scanf("%lf",&inicial); neteja_stdin(); } while (aux==0 || inicial<0); do { printf ("Nombre d'anys (no negatiu): "); aux=scanf("%d",&n); neteja_stdin(); } while (aux==0 || n<0); do { printf ("Inters anual (no negatiu): "); aux=scanf("%f",&interes); neteja_stdin(); } while (aux==0 || inters<0); do { printf ("Nombre de decimals de la moneda (no negatiu): "); aux=scanf("%d",&dec); neteja_stdin(); } while (aux==0 || dec<0); printf ("\nVersi 1: %lf\n",capital_rec1(inicial,inters,n,dec)); printf ("\nVersi 2: %lf\n",capital_rec2(inicial,inters,n,dec)); }
En aquest programa hem aplicat el clcul real que sefectua en les entitats bancries (o que caldria efectuar) per calcular el capital compost, ja que cal tenir en compte els arrodoniments de la moneda corresponent. Per aix hem codificat la funci arrodonir, mitjanant la qual, donat un valor
16
Recursivitat. Arbres
double i un valor unsigned int, sarrodoneix el double al nombre de decimals que indica lunsigned int. Hem de suposar que ja no tindreu cap problema per comprendre aquesta funci. Posteriorment, cal utilitzar-la en els clculs dels diversos capitals acumulats.
17
Recursivitat. Arbres
Pas 3 4 5 6 7 8 9
n 2 1 0
Instrucci que sexecuta 2 * factorial (1) 1 * factorial (0) factorial (0) producte pendent del pas 4 producte pendent del pas 3 producte pendent del pas 2 producte pendent del pas 1
Factorial
1 1 (1 * 1) 2 (2 * 1) 6 (3 * 2) 24 (4 * 6)
Clcul de fibonacci(4)
Pas 0 1 2 3 4 5 6 7 8 9 10 11 12 13 2 2 1 1 4 3 2 1 0 n Instrucci que sexecuta fibo(4) fibo(3) + fibo(2) fibo(2) + fibo(1) fibo(1) + fibo(0) fibo(1) fibo(0) pendent del pas 3 suma pendent del pas 3 fibo(1) pendent del pas 2 suma pendent del pas 2 fibo(1) + fibo(0) que s el fibo(2) pendent del pas 1 fibo(1) fibo(0) pendent del pas 8 suma pendent del pas 8 suma pendent del pas 1 fibo(2) fibo(2), fibo(1) fibo(2), fibo(1), fibo(0) fibo(2), fibo(1), fibo(0) fibo(2), fibo(1), 1 fibo(2), fibo(1) fibo(2), 1 fibo(2) 2 2, fibo(0) 2, 1 2 1 0 1 (1 + 0) 3 (2 + 1) 1 0 1 (1 + 0) 1 2 (1 + 1) Pila Fibonacci
Enteneu per qu la versi recursiva Fibonacci s molt ineficient? Fixeu-vos que van quedant un munt de crides pendents dexecutar en la pila. Quan arriba el moment de fer-ne lexecuci, sexecuten. Algunes ja shavien calculat abans, per lordinador no ho pot saber i les torna a executar. Enteneu que lordinador pot quedar penjat a causa de la saturaci de la pila? En aquest cas, la versi recursiva hauria de quedar totalment descartada.
18
Recursivitat. Arbres
I com que ja som coneixedors del tipus de dada pila, podem utilitzar-la gestionant nosaltres mateixos la memria disponible. Un subprograma pot tenir variables locals i parmetres (arguments). Quan es fa una crida recursiva al subprograma, els valors actuals de variables i parmetres shan de conservar. Tamb sha de conservar ladrea a la qual ha de tornar el control una vegada executat el subprograma cridat. En realitat, aquest procediment s el que sutilitza sempre que es fa la crida dun subprograma a un altre (encara que no hi hagi recursivitat). El procediment que es proposa per simular la recursivitat dun algorisme que tingui N parmetres i M variables locals consisteix a tenir N+M piles (o una pila de N+M valors per element) on es puguin guardar les imatges corresponents del moment en qu cal fer la crida i refer la recursivitat en un procs iteratiu. Utilitzarem les piles amb les dues operacions ja conegudes:
funci push (var top: ^node, elem: T) retorna natural; /* 0: O.K. - 1: Pila plena */ funci pop (var top: ^node, var elem: T) retorna natural; /* 0: O.K. - 1: Pila buida */
Ara solucionarem el clcul del factorial dun nombre natural simulant la recursivitat.
funci factorial (n: natural) retorna natural s var top: ^natural; r: natural; aux: natural; fivar top = NUL; /* Punter al capdamunt de la pila */ /* El segent mentre equival a anar guardant el valor n de manera que quan es tingui r=factorial(n-1) es pugui recuperar per calcular n*r */ mentre n > 0 fer si push (top, n) != 0 llavors ERROR("Pila plena"); avortar; fisi n = n - 1; fimentre r = 1; /* Soluci per lestat base */ /* El segent mentre equival a tornar de les diferents crides recursives recuperant els valors de la pila i fent els clculs oportuns */ mentre pop (top, aux) == 0 fer r = r * aux; fimentre retorna r; fifunci
En veure-ho daquesta manera ens adonem que ens podem estalviar lemmagatzematge en la pila del valor n, ja que consisteix a anar guardant els diferents valors des de n fins a 1 (de manera descendent), recuperar-los posteriorment dun en un i anar calculant r. En aquest cas tindrem la soluci iterativa coneguda per tothom:
funci factorial (n: natural) retorna natural s var r: natural; aux: natural; fivar r=1; aux=1; mentre aux <= n fer r = r*aux; aux = aux+1; fimentre retorna r; fifunci
19
Recursivitat. Arbres
20
Recursivitat. Arbres
a auxiliar.
2) Movent el disc inferior de T1 a T2. 3) Movent els N-1 discos existents de T3 a T2, utilitzant la torre T1 com
a auxiliar. Observeu que si els moviments dels apartats 1 i 3 respecten les regles (considerant noms els N-1 discos que mouen), llavors la totalitat dels moviments 1-2-3 tamb les respecten, ja que els discos que es mouen sempre sn de menys dimetre que els que ja estan situats en les torres. Per tant, sha aconseguit redefinir el problema de grau N en termes de grau N-1. Ens estem apropant a un estat base (un nic disc), on el moviment entre la torre font i la torre destinaci s immediat, s a dir, sense lajut de la torre auxiliar.
acci hanoi (N, FONT, DEST, AUXILIAR: natural) s si N==1 llavors escriure ("Posar disc de ",FONT," a ", DEST); /* Estat bsic */ sin hanoi (N-1, FONT, AUXILIAR, DEST); escriure ("Posar disc de ",FONT," a ", DEST); hanoi (N-1, AUXILIAR, DEST, FONT); fisi fiacci
Presentem, a continuaci, una versi no recursiva utilitzant piles per simular la recursi.
tipus sit_hanoi = tuple N, TF, TD, TA: natural; fituple /* El tipus sit_hanoi permet emmagatzemar una situaci concreta del problema */ node = tuple inf: sit_hanoi; seg: ^node; fituple /* El tipus node correspon al node per a una pila implementada com a llista */ fitipus acci hanoi (N, FONT, DEST, AUXILIAR: natural) s var top: ^node; sit: sit_hanoi; aux, crida: natural; fivar crida=1; mentre N>1 i crida==1 fer /* El segent mentre posa a la pila totes les primeres crides */ mentre N > 1 fer sit.N=N; sit.TF=FONT; sit.TD=DEST; sit.TA=AUXILIAR; si push (top, sit)!=0 llavors ERROR("Pila plena"); avortar; fisi N=N-1; aux=DEST; DEST=AUXILIAR; AUXILIAR=aux; fimentre escriure ("Posar disc de ",FONT," a ", DEST); crida=2; si pop(p,sit)==0 llavors
21
Recursivitat. Arbres
N=sit.N; FONT=sit.TF; DEST=sit.TD; AUXILIAR=sit.TA; escriure ("Posar disc de ",FONT," a ", DEST); /* Simularem la 2a crida a hanoi corresponent a la que acabem de tractar */ N=N-1; aux=FONT; FONT=AUXILIAR; AUXILIAR=aux; crida=1; fisi fimentre fiacci
Una simple ullada entre els algorismes recursiu i iteratiu permet concloure que la soluci recursiva del problema de les torres de Hanoi s molt ms compacta i ms fcil dentendre que la soluci no recursiva. De tota manera, s important disposar dun formalisme per traduir els processos recursius en processos no recursius, ja que alguns llenguatges no disposen de recursivitat i en certs problemes el cost de la recursivitat s molt significatiu.
que tots els elements que es trobin a la seva esquerra siguin ms petits o iguals que X i que tots els elements que es trobin a la seva dreta siguin ms grans o iguals que X. Per aconseguir-ho, probablement caldr moure diversos elements de la taula.
3) Es repeteixen els passos anteriors, per ara per als conjunts de dades que
dins la taula. Del que sha exposat es pot deduir que aquest algorisme s fcilment programable si sutilitza la recursi. Vegem-ne la versi recursiva. Seleccionarem un element X qualsevol. Considerarem, per exemple, t[0]. Comencem a recrrer la taula de dreta a esquerra comparant si els ele-
22
Recursivitat. Arbres
ments sn ms grans o iguals que X. Si un element no compleix la condici, sintercanvia amb X. Sinicia novament el recorregut a partir don ara est collocat X, per desquerra a dreta, comparant si els elements sn ms petits o iguals que X. Si un element no compleix la condici, sintercanvia amb X. Es repeteixen els passos anteriors (a partir don ara est collocat X) fins que lelement X troba la seva posici correcta dins la taula. Per ordenar una taula t[MAX] de T, caldria executar quicksort (0,MAX-1), on:
acci quicksort (inici, final: natural) s var esq, dre, pos: natural; situat: boole; aux: T; fivar esq = inici; dre = final; pos = inici; situat = fals; mentre no situat fer situat = cert; mentre t[dre].V >= t[pos].V i dre != pos fer dre = dre -1; fimentre si dre != pos llavors aux = t[pos]; t[pos] = t[dre]; t[dre] = aux; pos = dre; mentre t[esq].V <= t[pos].V i esq != pos fer esq = esq + 1; fimentre si esq != pos llavors situat = fals; aux = t[pos]; t[pos] = t[esq]; t[esq] = aux; pos = esq; fisi fisi fimentre /* En aquest moment l'element que es troba a la posici "pos" t tots els elements de la seva esquerra menors o iguals que ell i tots els elements de la seva dreta majors o iguals que ell. */ si inici < pos - 1 llavors quicksort (inici, pos - 1); fisi si final > pos + 1 llavors quicksort (pos + 1, final); fisi fiacci
Clculs matemtics asseguren que aquest algorisme s dordre (n * log2 n.). Encara que lalgorisme del quicksort en versi recursiva sigui clar, s possible augmentar-ne leficincia eliminant les crides recursives. La recursi s un instrument molt poders, per leficincia dexecuci s un factor molt important en un procs dordenaci que cal administrar molt b. Aquestes crides recursives es poden substituir utilitzant piles, cosa que dna lloc a la versi iterativa. Us atreviu a dissenyar-ne la versi iterativa?
23
Recursivitat. Arbres
2. Arbres
Un arbre s una estructura jerrquica aplicada sobre una collecci delements, anomenats nodes, un dels quals s conegut com a arrel. Entre els diferents nodes es crea una relaci o parentesc que dna lloc a termes com pare, fill, germ...
Un arbre de tipus T s una estructura homognia fruit de la concatenaci dun element de tipus T, anomenat arrel, amb un nombre finit darbres disjunts (que no tenen cap element en com), anomenats subarbres. Un cas particular darbre pot ser lestructura buida.
Observeu que la definici darbre ha estat recursiva, ja que per definir un arbre sha utilitzat el mateix concepte darbre. Lltima part de la definici (un arbre pot ser buit) constitueix lestat base de la definici recursiva que nassegura la finitud. Els arbres tenen una gran varietat daplicacions: representaci de frmules matemtiques, representaci darbres genealgics, anlisi de circuits elctrics, esquemes de continguts... Per, sobretot, sutilitzen en la gesti dels ndexs en els arxius seqencials indexats. Les caracterstiques i propietats dels arbres en general sn: !
a) Tot arbre no buit t un nic node arrel. b) Un node X s descendent directe dun node Y, si el node X s apuntat
grau dun arbre es defineix com el grau ms gran de tots els nodes de larbre.
h) El nivell dun node es defineix com el nombre de generacions entre
24
Recursivitat. Arbres
A s larrel. D, I, J, F, K i H sn nodes terminals fulles. B, C, E i G sn nodes interiors. E s pare de I i J, i aquests sn fills de E. G s pare de K, i aquest s fill de G. B s pare de D i E, i aquests sn fills de B. C s pare de F, G i H, i aquests sn fills de C. A s pare de B i C, i aquests sn fills de A. El grau de B s 2. El grau de larbre s 3, ja que C t grau 3 i s el grau ms gran. Laltura de larbre s 4, ja que s el nivell ms alt (per a les fulles I, J i K). A partir de la figura 3 i de la nostra experincia prvia, intum que informatitzar una estructura daquest estil implicar la utilitzaci de nodes en els quals emmagatzemarem les dades (A, B, C, D...) i els punters, tants com fills tingui aquell node. No informatitzarem, per, qualsevol tipus darbre, sin que anirem filtrant els tipus darbres interessants per al tractament informtic.
Un arbre ordenat s un arbre que t branques dels nodes ordenades o, millor dit, es poden enumerar. Un arbre binari s un arbre ordenat de grau 2. Per tant, cada node pot tenir, com a mxim, dos fills. Quan sordena un arbre binari sempre es pot distingir entre el subarbre esquerre (arbre que t com a arrel el fill esquerre) i el subarbre dret (arbre que t com a arrel el fill dret). Un arbre binari s complet si tots els seus nodes que no siguin fulles tenen dos fills i totes les fulles es troben al mateix nivell.
25
Recursivitat. Arbres
En un arbre complet es verificar que: Nombre de nodes = 2h 1 (h s laltura de larbre) La importncia dels arbres binaris radica en el seu dinamisme, la seva programaci senzilla, la no-linealitat i el fet que existeixen algorismes mitjanant els quals qualsevol estructura en arbre pot ser reduda a un arbre binari i, per tant, tenir el tractament informtic corresponent a un arbre binari.
Conversi a arbre binari No sinclou en els objectius daquest crdit la mecnica de transformaci de qualsevol arbre no binari en binari. En els llibres de la bibliografia especfica corresponents a aquest aspecte en trobareu les explicacions.
Un node dun arbre binari consta de tres parts: Una part que cont la informaci que es vol emmagatzemar en larbre. Una part que cont el lligam cap al fill esquerre. Contindr el valor NUL si no t fill esquerre. Una part que cont el lligam cap al fill dret. Contindr el valor
NUL si no t fill dret.
Per tant, si volem gestionar un arbre per emmagatzemar-hi dades dun cert tipus T, caldr tenir en compte la definici segent:
tipus node = tuple inf : T; /* cont la informaci */ esq, dre : ^node; /* punters als dos fills */ fituple
La figura 4 ens ho mostra grficament. Per tant s clar el segent: un arbre binari s una estructura ramificada de nodes per a la qual hi ha dhaver un punter inicial; les fulles tenen el valor NUL (N) en els dos punters; un arbre buit t en el punter inicial el valor NUL.
26
Recursivitat. Arbres
Evidentment, crear larbre no consisteix a fer res ms que crear el punter inicial. Cal tenir, per, la precauci dinicialitzar-lo amb el valor NUL.
2) Crrega dun arbre binari
No ens complicarem la vida. Simplement volem disposar dalgun mtode per carregar en memria un arbre binari que tinguem en paper per tal de poder comprovar posteriorment els algorismes de recorregut.
acci crrega (var arbre:^node) retorna natural s /* Argument arbre : Punter per apuntar larrel de larbre */ var element: T; sn: carcter; fivar si arbre != NUL llavors esborrar (arbre); fisi escriure ("Introdueixi lelement a inserir:"); llegir (element); assignar_memria (arbre); si arbre == NUL llavors escriure ("Larbre no pot crixer ms."); sin arbre^.inf = element; arbre^.esq = NUL; arbre^.dre = NUL; pregunta ("T fill per lesquerra?", sn, "SN"); si sn == 'S' llavors crrega (arbre^.esq); fisi /* crida recursiva */ escriure ("Situs en el node que t com a element", element); /* Pregunta perqu lusuari se situ en cas dhaver-se executat la crida recursiva i haver deixat "penjat" el node dret daquest element */ fisi pregunta ("T fill per la dreta?", sn, "SN"); si sn == 'S' llavors crrega (arbre^.dre); fisi /* crida recursiva */ fisi fiacci
3) Algorismes de recorregut
Els algorismes de recorregut sn els ms importants en el tractament darbres binaris en general, ja que recrrer un arbre significa visitar-ne els nodes sistemticament, de manera que tots siguin visitats una nica vegada.
27
Recursivitat. Arbres
Cal entendre per visita el fet de tractar la informaci que cont. No es considera visita el fet de passar pel node per consultar els punters esq i dre i aix poder passar als nodes fills corresponents. Hi ha tres maneres de fer el recorregut darbres binaris. Totes sn de naturalesa recursiva: preordre, inordre i postordre.
larrel, en segon lloc, el subarbre esquerre en preordre i, en tercer lloc, el subarbre dret en preordre.
b) El recorregut en inordre consisteix a visitar, en primer lloc, el sub-
arbre esquerre en inordre, en segon lloc, larrel i, en tercer lloc, el subarbre dret en inordre.
c) El recorregut en postordre consisteix a visitar, en primer lloc, el
subarbre esquerre en postordre, en segon lloc, el subarbre dret en postordre i, en tercer lloc, larrel.
Observeu que les tres definicions sn recursives i, per tant, la codificaci dels tres recorreguts ser recursiva.
acci preordre (arbre:^node) s si arbre != NUL llavors tractament (arbre^.inf); preordre (arbre^.esq); preordre (arbre^.dre); fisi fiacci acci inordre (arbre:^node) s si arbre != NUL llavors inordre (arbre^.esq); tractament (arbre^.inf); inordre (arbre^.dre); fisi fiacci acci postordre (arbre:^node) s si arbre != NUL llavors postordre (arbre^.esq); postordre (arbre^.dre); tractament (arbre^.inf); fisi fiacci
28
Recursivitat. Arbres
un arbre binari genric? Noms hi ha una manera de fer-ho: considerar un dels tres recorreguts possibles (preordre, inordre i postordre) i anar cercant fins a trobar lelement o fins a arribar al final del recorregut sense xit. Gens eficient! Aquest algorisme s tan ineficient com ho s la recerca seqencial en taules. Recordeu com podem millorar el cost lineal de la recerca seqencial? Ho podem aconseguir en les taules ordenades, ja que llavors es pot aplicar la recerca dicotmica. En el tipus de dada arbre succeeix una cosa semblant i per aquest motiu interessa treballar amb arbres binaris de recerca.
Un arbre binari de recerca s un arbre binari tal que: tots els valors emmagatzemats en el subarbre esquerre de qualsevol node T han de ser ms petits o iguals que el valor emmagatzemat en el node T; tots els valors emmagatzemats en el subarbre dret de qualsevol node T han de ser ms grans que el valor emmagatzemat en el node T.
Intuu per on anir la recerca dun determinat element? Donat un node, si lelement cercat t un valor ms petit que el valor emmagatzemat en el node, continuarem la recerca pel subarbre esquerre, i si el seu valor s ms gran, seguirem la recerca pel subarbre dret. Evidentment, si el valor coincideix amb el valor del node, aturarem la recerca amb un resultat positiu. Fixeu-vos que s una recerca dicotmica en arbres, ja que en cada node obviem un dels dos subarbres mitjanant el procs de recerca. Aquests arbres no solament tenen importncia grcies al seu algorisme de recerca, sin que a ms permeten realitzar de manera eficient les operacions dinserci i eliminaci de manera que larbre mantingui sempre la categoria darbre de recerca.
Figura 5. Arbre binari de recerca de valors enters
Comparaci amb altres tipus de dades Observeu que en les taules ordenades la recerca s eficient, per mantenir-la ordenada s costs. En les llistes ordenades sn costosos el manteniment i la recerca.
29
Recursivitat. Arbres
La figura 5 ens mostra un arbre binari de recerca. Observeu que un recorregut en inordre provoca una classificaci ascendent de tots els seus nodes: 10 - 20 - 30 - 35 - 40 - 50 - 55 - 60 - 62 - 70 - 80 Vegem els algorismes de recerca, inserci i esborrament en arbres binaris de recerca, suposant que no hi ha elements repetits (cas ms freqent).
30
Recursivitat. Arbres
Observeu que es tracta dun procs recursiu que finalitza quan es dna alguna de les dues situacions segents: Lelement coincideix amb el valor emmagatzemat en el node arrel de larbre actual, fet que indica que lelement ja existia en larbre. Larbre actual s buit, fet que indica que som en el subarbre on cal inserir el valor.
funci inserir (var arbre:^node, elem:T) retorna natural s /* Arguments: arbre: Punter a larrel de larbre elem: Dada a inserir Retorna: 0 : Inserci efectuada amb xit 1 : Error per manca de memria 2 : Ja existeix un element amb el mateix identificador */ var res: natural; fivar /* per emmagatzemar el resultat a retornar */ si arbre == NUL llavors assignar_memria (arbre); si arbre == NUL llavors retorna 1: fisi arbre^.esq = NUL; arbre^.dre = NUL; arbre^.inf = elem; retorna 0; sin opci cas s_menor* (arbre^.inf, elem): res = inserir (arbre^.dre, elem); cas s_major* (arbre^.inf, elem): res = inserir (arbre^.esq, elem; altrament: res = 2; fiopci retorna res; fisi fifunci funci s_menor* (ele1: T, ele2: T) retorna boole s /* Codi que comprovi si la part T* dele1 s ms petita que la dele2 */ fifunci funci s_major* (ele1: T, ele2: T) retorna boole s /* Codi que comprovi si la part T* dele1 s ms gran que la dele2 */ fifunci
31
Recursivitat. Arbres
Si lelement que sha desborrar es troba en un node que t dos nodes fill, el node que cont el valor que sha deliminar se substitueix adequadament pel node que s ms a la dreta del subarbre esquerre o pel node que s ms a lesquerra del subarbre dret. Comprovarem el funcionament dels passos anteriors. Suposem que volem eliminar el valor 10 de larbre de la figura 6.
Figura 6. Arbre binari de recerca on cal eliminar el valor 10 Figura 7. Arbre binari de recerca una vegada eliminat el valor 10
En efectuar la recerca el trobem en una fulla. En aquest cas, el node selimina i observem que larbre obtingut (figura 7) continua essent de recerca. Suposem que volem eliminar el valor 40 en larbre de la figura 7. En efectuar la recerca, el trobem en un node interior, el qual nicament t un fill. Segons les regles convingudes, se substitueix pel node fill i observem que larbre obtingut (figura 8) continua essent de recerca.
Figura 8. Arbre binari de recerca de la figura 7 una vegada eliminat el valor 40
Suposem que volem eliminar el valor 60. Desprs de cercar-lo el trobem en un node interior que t dos fills. Segons les regles convingudes, cal substituir-lo pel node de ms a lesquerra del subarbre dret (node que cont el valor 62, i sobt larbre de la figura 9) o pel node de ms a la dreta del subarbre esquerre (node que cont el valor 55, i sobt larbre de la figura 10).
32
Recursivitat. Arbres
Figura 9. Arbre binari de recerca de la figura 8 una vegada eliminat el valor 60 substituint-lo pel node de ms a l'esquerra del subarbre dret
Figura 10. Arbre binari de recerca de la figura 8 una vegada eliminat el valor 60 substituint-lo pel node ms a la dreta del subarbre esquerre
Observem que tant en un cas (procs que obt larbre de la figura 9) com en laltre (procs que obt larbre de la figura 10), els nodes escollits per substituir el node que contenia el valor 60 (62 i 55 de la figura 8) no tenien cap fill. s clar que el node que contenia el valor 62 podria haver tingut fills per la dreta (i continuaria essent el node de ms a lesquerra del subarbre dret figura 8), de la mateixa manera que el node que contenia el valor 55 podria haver tingut fills per lesquerra (i continuaria essent el node de ms a la dreta del subarbre esquerre figura 8). Evidentment, els possibles subarbres fill dels nodes que contenen els valors 62 i 55 no poden desaparixer i, per tant: En la figura 9, el possible subarbre dret del node que contenia el valor 62 en la figura 8 hauria dhaver passat a ser subarbre esquerre del node que cont el valor 70 (o mantenir-se com a subarbre dret del node que cont el valor 62 si el node eliminat no tenia subarbre dret). En la figura 10, el possible subarbre esquerre del node que contenia el valor 55 en la figura 8 hauria dhaver continuat essent el subarbre esquerre del node que cont el valor 55 (o passar a ser el subarbre dret del subarbre esquerre del node eliminat si hagus existit). Lestructura de larbre resultant s diferent si sexecuta luna o laltra opci, per en tots dos casos continua tractant-se dun arbre binari de recerca. Quin resultat final us sembla ms adequat? s ms adequat el resultat final de la figura 9, ja que deixa un arbre ms ben repartit. Aix no vol dir que shagi daplicar sempre lelecci que ha possibilitat aquest resultat final, ja que aquest depn de la situaci de partida. Aix doncs, ja estem en condicions de presentar el pseudocodi de la funci esborrar en un arbre binari de recerca.
funci esborrar(var arbre:^node, var elem:T, ref:T*) retorna natural s /* Arguments: arbre: Punter a larrel de larbre elem: Variable on sha de recollir lelement a esborrar ref: Dada de tipus T* que identifica lelement a esborrar Retorna: 0 : Esborrament efectuat amb xit 1 : Error ja que no existeix un tal element identificat per ref */ var res: natural; /* per emmagatzemar el resultat a retornar */
33
Recursivitat. Arbres
aux, auxbis: ^node; fivar opci cas arbre == NUL: res = 1; cas s_major(arbre^.inf, ref): res = esborrar (arbre^.esq, elem, ref); cas s_menor(arbre^.inf, ref): res = esborrar (arbre^.dre, elem, ref); altrament: /* lelement a esborrar est en el node apuntat per arbre */ aux = arbre; res = 0; element = arbre^.inf; opci cas aux^.esq == NUL i aux^.dre == NUL: /* s una fulla */ arbre = NUL; alliberar_memria (aux); cas aux^.esq == NUL i aux^.dre != NUL: /* noms fill dret */ arbre = aux^.dre; alliberar_memria (aux); cas aux^.esq != NUL i aux^.dre == NUL: /* noms fill esquerre */ arbre = aux^.esq; alliberar_memria (aux); altrament: /* dos fills */ /* substitum pel node ms a la dreta del subarbre de lesquerra */ auxbis = aux^.esq; mentre auxbis^.dre != NUL fer aux = auxbis; auxbis = auxbis^.dre; fimentre si aux == arbre llavors aux^.esq = auxbis^.esq; sin aux^.dre = auxbis^.esq fisi arbre^.inf = auxbis^.inf; alliberar_memria (auxbis); fiopci fiopci retorna res; fifunci
Observeu el carcter recursiu de lalgorisme. Tamb s important remarcar que en cas de substituci per lelement que es troba ms a la dreta del subarbre esquerre no se substitueix node per node, sin lelement que sha desborrar per lelement del node ms a la dreta del subarbre esquerre.
34
Recursivitat. Arbres
Oi que no estan ben repartits? Aix provoca que la recerca de valors no aprofiti leficincia que el seu disseny aporta en ls del procs dicotmic. Per solucionar aquesta situaci apareix el concepte darbre balancejat.
Un arbre balancejat s un arbre binari de recerca tal que, per a qualsevol node, les altures dels subarbres dret i esquerre no poden diferir en ms duna unitat.
La idea central s la darreglar larbre desprs de les insercions i les eliminacions de manera que es mantingui lequilibri. Per poder mantenir aquest equilibri, cal tenir informaci referent a lequilibri de cada node de larbre. Aix provoca laparici del concepte factor dequilibri dun node.
El factor dequilibri dun node s el resultat de la resta de laltura del subarbre dret menys laltura del subarbre esquerre.
Perqu larbre sigui balancejat cal mantenir en tots els nodes el factor dequilibri en els valors 1, 0 o 1. Aquest factor semmagatzema en cada node i es recalcula, de manera adequada, en cada inserci i eliminaci. En cas de prdua dequilibri en algun node es reestructura larbre per mantenir-lo com a arbre balancejat. De lapartat anterior es dedueix que la implementaci dun node per a arbre balancejat necessita un nou apartat:
tipus node = tuple inf : T; /* cont la informaci */ esq, dre : ^node; /* punters als dos fills */ fe : enter; fituple
El nou camp fe hauria de valer sempre -1, 0 o 1, per en determinats moments pot valer -2 o 2, a causa de la prdua momentnia de lequilibri. Ara presentem el funcionament dels algorismes dinserci i esborrament per als arbres balancejats. No arribarem a escriuren el pseudocodi, ho deixem per a vosaltres. Us hi animeu? Lalgorisme de recerca no canvia respecte als arbres binaris de recerca.
35
Recursivitat. Arbres
dequilibri (FE, a partir dara) que, evidentment, ser zero. Cal tornar enrere pel cam de recerca daquest nou node i recalcular els FE dels nodes pels quals es passa, fins a trobar un node que perdi lequilibri o fins a arribar a larrel sense que perdi lequilibri. Si es localitza un node amb prdua dequilibri, cal refer larbre en aquest node i no cal continuar recalculant lFE per a la resta de nodes, ja que aquest mtode ens assegura que no haur variat. Per refer larbre cal aplicar el mtode adequat segons quina situaci es produeixi, que pot ser una de les quatre que mostra la figura 13.
Figura 13. Mtodes a aplicar per refer larbre i recuperar el factor dequilibri
36
Recursivitat. Arbres
No hi ha res millor que un exemple per entendre les diferents situacions que es poden presentar. Volem construir un arbre balancejat a partir de la seqncia de valors 55 - 40 - 13 - 60 - 72 - 58 - 29. La figura 14 ens mostra els diferents passos que hem de seguir.
Figura 14. Creaci darbre balancejat provocat per les insercions 55, 40, 13, 60, 72, 58 i 29
37
Recursivitat. Arbres
node, es retorna pel cam de recerca daquest nou node fins a larrel, recalculant els FE dels nodes pels quals es passa fins a arribar a larrel. Cal reestructurar larbre en aquest node en el qual sha perdut lequilibri. A diferncia de lalgorisme dinserci, cal comprovar lFE fins a larrel, ja que hi pot haver diversos nodes en els quals es perdi lequilibri. La figura 15 ens mostra diverses situacions que es presenten en eliminar valors en un arbre balancejat.
Figura 15. Processos deliminaci de valors en arbres balancejats
38
Recursivitat. Arbres
Lanlisi matemtica dels algorismes dinserci i eliminaci demostra que tots sn dordre logartmic. Daltra banda, diverses anlisis mostren que sn ms freqents les rotacions en les operacions dinserci que en les deliminaci.
Un arbre multicam s un arbre balancejat que en un node cont diversos valors i diversos punters a altres nodes. Si considerem que cont N valors, haur de contenir N + 1 punters.
Les caselles Inf1, Inf2, Inf3 i Inf4 contindrien els valors i les caselles P1, P2, P3, P4 i P5 contindrien els punters a nous nodes. Des dun node es pot tenir accs a cinc nodes diferents, s a dir, disposem de cinc camins a seguir. Es veu clar ara don prov el nom darbres multicam? Hi ha diferents tipus darbres multicam. En presentarem dos de molt coneguts: els arbres B i els arbres B+.
39
Recursivitat. Arbres
2.4.1. Arbres B
Els arbres B sn una generalitzaci dels arbres balancejats per aconseguir arbres multicam. Vegem-ne la definici.
Autors dels arbres B El disseny dels arbres B s obra de Bayer i McCreight el 1970. El seu nom prov de Bayer? s una incgnita.
Un arbre B dordre d s un arbre que t les caracterstiques segents: Cada node, excepte larrel, cont entre d i 2d elements. Cada node, excepte larrel i les fulles, t entre d + 1 i 2d + 1 fills. El node arrel o no t fills (perqu s una fulla) o en t dos com a mnim. Totes les fulles es troben en un mateix nivell (balancejat perfecte). Els elements emmagatzemats en un node estan ordenats de ms petit a ms gran (desquerra a dreta). Cada element dun node que no s fulla t dos fills. Tots els elements del seu subarbre esquerre sn ms petits que ell i tots els elements del seu subarbre dret sn ms grans que ell.
Per poder treballar amb arbres B, cal que en cada node hi hagi informaci referent al nombre de dades que emmagatzema en un moment donat. Hi ha diferents maneres de poder tenir aquesta informaci: Mitjanant una dada afegida que permet obtenir aquesta informaci, de manera que lestructura dun node seria semblant a aquesta:
Es pot observar que tenim 2d + 1 punters (P1, P2, P3,..., P2d + 1) i 2d valors (Inf1, Inf2,..., Inf2d). La marca X correspondria a la quantitat de valors que en un determinat moment cont el node, que exceptuant larrel ha de ser sempre entre d i 2d. Sense una dada afegida i calculant el valor corresponent com a quantitat, disminuda en una unitat, de punters amb valor no nul. Aquest funcionament s possible en els nodes interiors, per no en les fulles, ja que en aquestes tot punter s nul. De fet, podrem considerar estructures de nodes diferents per als nodes interiors i per a les fulles. En les fulles no fan falta els punters, per en canvi s que cal saber quants valors estan emmagatzemant en un moment donat.
40
Recursivitat. Arbres
Algorisme de recerca
Lalgorisme de recerca per a arbres multicam no s altra cosa que una generalitzaci de lalgorisme de recerca per a arbres binaris. Vegem-ne el pseudocodi.
funci recerca (arbre:^node, var elem:T, ref: T*) retorna natural s /* Arguments: arbre: Punter a larrel de larbre elem: Variable on sha de recollir lelement cercat ref: Dada que identifica lelement a cercar Retorna: 0 : Recerca efectuada amb xit 1 : Element cercat no trobat */ var res: natural; fivar /* per emmagatzemar el resultat a retornar */ si arbre == NUL llavors retorna 1; fisi opci cas s_incls_en_el_node (arbre, ref, elem): res = 0; cas s_major (arbre^.inf1, ref): res = recerca (arbre^.P1, elem, ref); cas s_menor (arbre^.inf1, ref): res = recerca (arbre^.P2, elem, ref); cas s_menor (arbre^.inf2, ref): res = recerca (arbre^.P3, elem, ref); ... cas s_menor (arbre^.inf2d, ref): res = recerca (arbre^.P2d+1, elem, ref); fiopci retorna res; fifunci funci s_incls_en_el_node (p: ^node, ref: T*, var elem: T) retorna boole s /* Codi que comprovi si en el node apuntat per p hi ha un element amb part T* igual a ref. En aquest cas retorna cert i copia lelement en el parmetre elem. En cas contrari, retorna fals. */ fifunci
Figura 16. Exemple darbre B dordre 2
La figura 16 ens mostra la representaci grfica dun arbre B dordre 2. Primer de tot, observem que no representem les caselles corresponents a punters en cap node. Cada fletxa parteix duna casella punter i apunta el node corresponent. Daltra banda, hem de tenir clar que cada node cont fins a 4 caselles informaci, per noms representem les caselles que contenen valor. Per tant, veiem nodes amb 1, 2, 3 o 4 valors. Tamb observem que per poder fer el seguiment corresponent de lalgorisme de recerca hem numerat els nodes com a Node0, Node1,..., Node9. En la realitat, els nodes no estan numerats.
41
Recursivitat. Arbres
1) Recerca de lelement 77
Visitem larrel (node 0) i, en comparar el valor cercat 77 amb el valor 56 del node, com que 77 s ms gran que 56, seguim pel punter (fletxa) de la dreta del valor 56, la qual ens porta al node 2. Visitem el node 2, on trobem el valor cercat.
2) Recerca de lelement 79
Visitem larrel (node 0), el qual ens envia al node 2. Visitem el node 2, on posicionem el valor cercat 79 entre els valors 77 i 84, la qual cosa ens porta a seguir el cam cap al node 8. Visitem el node 8, on trobem el valor cercat.
3) Recerca de lelement 80
Visitem larrel (node 0), el qual ens envia al node 2. Visitem el node 2, el qual ens envia al node 9. Visitem el node 9, on no hi ha lelement cercat. Ja som en una fulla. La recerca ha finalitzat sense trobar lelement desitjat.
Algorisme dinserci
Els arbres B creixen de baix cap a dalt: de les fulles cap a larrel. Lalgorisme consisteix, en primer lloc, a aplicar lalgorisme de recerca per situarse en el node fulla, on hi hauria dhaver lelement a inserir. Una vegada en el node, hi ha diferents possibilitats:
1) Si hi ha espai (el node cont menys de 2d elements), sinsereix adequa-
divideix en dos (en realitat, es crea dinmicament un nou node), i els 2d + 1 elements (els 2d que ja existien en la fulla, ms lelement que cal inserir) es distribueixen ordenadament entre els dos nodes fulla, amb d valors en cada node fulla (els d valors ms petits en el node fulla esquerre i els d valors ms grans en el node fulla dret). Aleshores lelement central puja cap al node pare del node fulla inicial i shi insereix adequadament. La inserci en el node pare consisteix a repetir el mateix procs, cosa que pot provocar la creaci dun nou node amb la pujada del valor central cap al pare corresponent. Quan el node pare en qu cal inserir un element s el node arrel de larbre i ja no hi ha espai disponible, aquest provoca la creaci de dos nodes nous (en lloc de noms un!), ja que lun s el corresponent al procs normal i laltre, al nou node arrel (el node pare al qual puja lelement central).
Terminologia anglesa El procs descrit, que consisteix en la divisi dun node en dos, en qu es reparteixen els valors i el valor central passa al node pare, sanomena split en terminologia informtica anglesa. Per aix s molt normal indicar quan cal aplicar el procs sobre un node A, que el node A esplita, en un clar abs de terminologia. Per estareu dacord que dir el node A esplita s molt clar i molt ms simple que dir es crea un nou node que recull la meitat superior del conjunt ordenat de valors format pels
42
Recursivitat. Arbres
valors del node A ms el valor a inserir; el node A es queda amb la meitat inferior del mateix conjunt de valors i el valor central sinsereix en el node pare del node A. Per tant, utilitzarem lexpressi el node esplita per fer referncia a tot aquest procs.
Vegem-ne un exemple per entendre les diferents situacions que es poden presentar. Volem construir un arbre B dordre 2 a partir de la seqncia de valors 5 - 22 - 24 - 12 - 20 - 16 - 10 - 26 - 8 - 46 - 15 - 19 - 43 - 14 - 55 - 30 - 61. La figura 17 ens mostra els passos que hem de seguir.
Figura 17. Creaci dun arbre B amb els valors 5, 22, 24, 12, 20, 16, 10, 26, 8, 46, 15, 19, 43, 14, 55, 30 i 61
43
Recursivitat. Arbres
44
Recursivitat. Arbres
Algorisme deliminaci
Lalgorisme deliminaci ha de fer una cosa contrria a lalgorisme dinserci, ja que un node (excepte larrel) mai no pot quedar amb menys de d valors. Per tant, hi haur algun procs invers a lsplit, consistent en una fusi de nodes. En efecte, lalgorisme consisteix a cercar lelement que sha desborrar i, una vegada localitzat, hi ha dues possibilitats:
1) Si el valor que sha desborrar es troba en una fulla, se suprimeix. 2) Si el valor que sha desborrar es troba en un node no fulla, se substitueix
pel valor que es troba ms a la dreta del subarbre apuntat pel seu punter esquerre o pel valor que es troba ms a lesquerra del subarbre apuntat pel seu punter dret. Aquest valor sempre es troba en una fulla. En qualsevol dels dos casos, sha de verificar si la fulla que ha acabat perdent el valor continua tenint d valors com a mnim. Si s aix, no sha de fer res ms. En cas contrari, sha daplicar una reorganitzaci o fusi de la fulla amb la fulla germana de la dreta, si existeix, o amb la fulla germana de lesquerra (si no tenia germana per la dreta). Tota fulla que no sigui arrel sempre t una fulla germana. Reorganitzarem quan la fulla germana tingui ms de d valors. En aquest cas, aquesta cedir valors a la fulla que ha perdut lelement suprimit. Aquesta cessi comporta un moviment del valor mitj existent en el pare de les dues fulles. Fusionarem quan la fulla germana tingui exactament d valors. En aquest cas, passa a haver-hi una nica fulla que cont els valors de les dues ms el valor mitj que residia en el pare. Per tant, el pare es queda amb un valor menys i cal aplicar-hi el mateix procs de comprovaci que sobre la quantitat de valors que cont. Si s inferior a d cal aplicar-hi el mateix procs de reorganitzaci o fusi. Vegem exemples deliminaci sobre el darrer arbre de la figura 17. Suposem que volem eliminar els valors 20 - 19 - 24 - 22 - 43 - 14 - 46 - 16. La figura 18 ens mostra els passos que hem de seguir.
45
Recursivitat. Arbres
46
Recursivitat. Arbres
2.4.2. Arbres B+
Els arbres B+ sn molt semblants als arbres B. La caracterstica principal daquests arbres s que tots els valors es troben en les fulles. Per tant: Qualsevol cam des de larrel per arribar a un element t la mateixa longitud. En els nodes interiors no cal tenir emmagatzemats els elements sencers, que es trobaran en les fulles. Noms cal tenir-hi emmagatzemats els valors de classificaci. Un arbre B+ dordre d s un arbre que verifica el segent: Cada node, excepte larrel, cont entre d i 2d valors de classificaci. Cada node, excepte larrel i les fulles, t entre d + 1 i 2d + 1 fills. El node arrel o no t fills (perqu s una fulla) o en t dos com a mnim. Totes les fulles es troben a un mateix nivell (balancejat perfecte) i sn les que contenen els elements que emmagatzema larbre. Els valors emmagatzemats dins un node estan ordenats de ms petit a ms gran (desquerra a dreta). Cada valor dun node interior t dos fills. Tots els valors del seu subarbre esquerre sn ms petits que ell i tots els valors del seu subarbre dret sn ms grans o iguals que ell.
Observeu que, a diferncia dels arbres B, en els quals tots els elements del subarbre dret de qualsevol element sn ms grans que lelement en qes-
47
Recursivitat. Arbres
ti, en els arbres B+ tots els valors del subarbre dret de qualsevol valor sn ms grans o iguals que el valor en qesti. Observeu, tamb, que en el pargraf anterior utilitzem el terme element per fer referncia al contingut dels nodes dels arbres B i el terme valor per fer referncia al contingut dels nodes dels arbres B+, ja que en aquests els elements noms sn en els nodes fulles. En els arbres B+ sevita la costosa operaci de reorganitzaci, per aix ja ho comprovarem en lalgorisme deliminaci corresponent.
Algorisme de recerca
s molt similar al dels arbres B, per amb la particularitat que en trobar el valor cercat en un node interior, cal continuar la recerca pel node apuntat per la dreta. El fet que un valor de recerca existeixi en un node interior no implica que hi hagi un element amb aquell valor en una de les fulles; simplement vol dir que en algun moment de la vida de larbre s que havia existit. Podrem constatar aquest fet en aplicar lalgorisme deliminaci.
Algorisme dinserci
s molt similar al dels arbres B, per amb la particularitat que quan una fulla no t ms espai i saplica el procs de split, lelement central es mant en la nova fulla (que quedar amb d + 1 valors) i una cpia del seu valor de classificaci passa a afegir-se al node pare de la fulla inicial. En els arbres B, era lelement central i no pas el valor de classificaci el que passava a formar part del node pare. En canvi, laplicaci del procs de split a un node interior s idntica a la que saplica en els arbres B. La figura 19 ens en mostra un exemple.
Figura 19. Exemple dinserci en un arbre B+ dordre 1
48
Recursivitat. Arbres
Algorisme deliminaci
s molt ms simple que en arbres B. Aix s degut al fet que els elements que shan deliminar sempre es troben a les fulles i no hi ha cap problema que el valor de classificaci corresponent a lelement eliminat continu estant en nodes interiors, tal com havem comentat en lalgorisme de recerca. Tenim dues possibilitats:
1) Si en eliminar un element la fulla queda amb d valors com a mnim, no
es fa res ms, encara que en algun node interior o en el node arrel hi hagi una cpia del valor de classificaci de lelement eliminat.
2) Si en eliminar un element la fulla queda amb menys de d valors, cal in-
tentar fer una reorganitzaci de valors en les fulles i en lndex. Caldr fusionar quan no hi hagi ms remei. La figura 20 ens en mostra un exemple.
Figura 20. Exemple deliminaci en un arbre B+ dordre 1
49
Recursivitat. Arbres
La figura 21 ens mostra un arxiu de dades amb diferents camps pel qual es vol disposar daccs directe i seqencial per valor de dos camps. Per aconseguir-ho tenim la necessitat de dos ndexs, tal com sobserva en la figura 21.
Figura 21. Exemple dun arxiu de dades indexat per dos camps diferents
En lexemple sutilitza un ndex lineal simple. Podrem, per, utilitzar els arbres B per als ndexs, de manera que lelement a emmagatzemar en les 2d caselles de cada node sigui la parella (clau, punter). Aix, si suposem arbres B dordre 1 i que es produeix la successi dinsercions en el mateix ordre en qu tenim els registres en larxiu de dades de la figura 21, podem anar construint els dos arbres B (un per a cada ndex). La figura 22 ens mostra els passos que se succeirien. Observeu que la instrucci llegir=_fi, facilitada pel sistema gestor darxius indexat, per a cercar el registre amb cognom Coromina per a lndex cognom aplicar lalgorisme de recerca per a aquest ndex. Trobar el valor Coromina en el node arrel acompanyat del valor 6, que indica ladrea on es troba el corresponent registre en larxiu (o zona) de dades. Fixeu-vos que per aconseguir laccs seqencial per valor segons una via daccs simplement cal dissenyar un algorisme dinordre generalitzat per als diferents elements de cada node. Aix, a partir de Coromina, passar al segent implicaria continuar pel cam que indica el seu punter dret. Anirem aix a Esteve. El recorregut preordre generalitzat ens portaria, posteriorment, a Miralles, Oll i Pelfort. Refem els passos de la figura 22 per al cas que els ndexs siguin arbres B+ dordre 1. La figura 23 ens mostra la seqncia de passos.
50
Recursivitat. Arbres
51
Recursivitat. Arbres
52
Recursivitat. Arbres
Observeu que en els nodes interiors dels arbres B+ noms hi ha el valor clau (valor de classificaci), mentre que en les fulles s on es troben el valor clau i ladrea, on hi ha la posici del registre corresponent a la zona de dades. Fixeu-vos que en cas de mantenir els nodes fulla encadenats (cosa independent de la gesti dun arbre B+), laccs seqencial pel valor de la via daccs corresponent seria molt fcil, ja que ens trobem Brito, Coromina, Esteve, Miralles, Oll i Pelfort. Si en lloc duna cadena simple es mant una doble cadena, tindrem el mateix accs seqencial per valor cap endavant i cap enrere.