Laborator 5

Arbori multicăi

Aplicatia 1

Sa se redacteze un program interactiv care implementeaza urmatoarele functii pentru prelucrarea unui arbore B de ordinul 2, avand siruri de caractere pe post de chei (deci o pagina din arbore va contine intre 2 si 4 siruri de caractere):

    • o functie pentru initializarea arborelui;

    • o functie pentru inserarea de chei in arbore

    • o functie pentru suprimarea de chei din arbore

    • o functie pentru cautarea unei chei in arbore, care contorizeaza si numarul de comparatii care se executa in timpul cautarii;

  • o functie pentru afisarea arborelui in preordine, cu indentarea nivelelor;

    • o functie care calculeaza inaltimea arborelui;

    • o functie care returneaza numarul de pagini din arbore;

    • o functie care, primind o cheie existenta in arbore, returneaza cheia din arbore imediat mai mica valoric (implementarea trebuie sa fie optima).

rezolvare

Aplicatia 2

Sa se redacteze un program interactiv care implementeaza urmatoarele functii pentru prelucrarea unui arbore B de ordinul 2, avand siruri de caractere pe post de chei (deci o pagina din arbore va contine intre 2 si 4 siruri de caractere):

    • o functie pentru initializarea arborelui;

    • o functie pentru inserarea de chei in arbore \

    • o functie pentru suprimarea de chei din arbore

    • o functie pentru cautarea de chei in arbore, care contorizeaza si numarul de comparatii care se executa in timpul cautarii;

    • o functie pentru afisarea arborelui in preordine, cu indentarea nivelelor;

    • o functie care returneaza cea mai mare cheie din arbore;

    • o functie care returneaza numarul de chei din arbore;

    • o functie care, primind o cheie existenta in arbore, returneaza cheia din arbore imediat mai mare valoric (implementarea trebuie sa fie optima).

rezolvare

arborib.h

#define N 2

#define NN (N*2)

typedef int TipCheie;

struct Nod

{

TipCheie cheie;

struct Pagina* p;

int contor;

};

typedef struct Nod Nod;

struct Pagina

{

int m;

struct Pagina* p0;

Nod e[NN + 1];

};

typedef struct Pagina Pagina;

Pagina* insereaza(Pagina *pag, TipCheie x, Nod *nod);

void afisare(Pagina *arbore, int nivel);

Pagina* suprima(Pagina *pag, TipCheie x, Nod *nod);

int numarPagini(Pagina *arbore,int count);

int numarPaginiNivel(Pagina *arbore,int count,int nivelCurent,int nivelCautat);

int inaltimeArbore(Pagina* arbore,int nivel);

arborib.c

#include <stdlib.h>

#include <stdio.h>

#include "arborib.h"

Nod v;

Pagina* insereaza(Pagina *pag, TipCheie x, Nod *nod)

{

int i, s, d, mij;

Pagina *q, *r;

if (!nod)

{

v.cheie = x;

v.contor = 1;

v.p = NULL;

}

else

v = *nod;

if (pag == NULL) //daca nu exista radacina

{

pag = (Pagina*)calloc(sizeof(Pagina), 1);

pag->e[++pag->m] = v;

return pag;

}

//se cauta binar pozitia cheii x in pagina curenta

s = 1;

d = pag->m;

while (s <= d)

{

mij = (s + d) / 2;

if (pag->e[mij].cheie == x) //gasit

{

pag->e[mij].contor++;

return pag;

}

if (x < pag->e[mij].cheie)

d = mij - 1;

else

s = mij + 1;

}

//daca este pagina terminala sau daca se propaga insertia

if (pag->p0 == NULL || nod)

{

if (pag->m < NN) //se poate adauga un nod in pagina curenta

{

++pag->m;

for (i = pag->m; i > d + 1; i--)

pag->e[i] = pag->e[i - 1];

pag->e[i] = v;

}

//pagina curenta pag este plina => supradepasire => pagina trebuie scindata

else

{

Pagina *a = pag;

Pagina *b = (Pagina*)calloc(sizeof(Pagina), 1);

pag = (Pagina*)calloc(sizeof(Pagina), 1);

//scindarea paginii curente

for (i = 1; i <= N; i++)

b->e[i] = a->e[i + N];

a->m = b->m = N;

//cheia noudului v e cheia de scindare

if (v.cheie > a->e[N].cheie && v.cheie < b->e[1].cheie)

pag->e[++pag->m] = v;

else

{

//ultima cheie a nodului a este folosita la scindare

if (v.cheie < a->e[N].cheie)

{

pag->e[++pag->m] = a->e[N];

for (i = a->m; i > 1 && a->e[i - 1].cheie > v.cheie; i--)

a->e[i] = a->e[i - 1];

a->e[i] = v;

}

//prima cheie a nodului a este folosita la scindare

else

{

pag->e[++pag->m] = b->e[1];

for (i = 1; i < b->m && b->e[i + 1].cheie < v.cheie; i++)

b->e[i] = b->e[i + 1];

b->e[i] = v;

}

}

//se refac legaturile intre pagini

b->p0 = pag->e[1].p; //prima legatura a paginii b devine legatura nodului parinte

pag->p0 = a; //prima legatura a nodului parinte devine fostul vecin stanga

pag->e[1].p = b; //a doua legatura a nodului parinte devine fostul vecin dreapta

}

}

else

{

if (d == 0) //s-a ajuns la cel mai din stanga element => prima legatura

q = pag->p0;

else

q = pag->e[d].p;

r = insereaza(q, x, NULL);

if (r != q) //daca pagina in care s-a inserat s-a scindat <=> arborele crescut cu un nivel

{

/*se incearca inserarea nodului din pagina scindata in pagina curenta

in caz de succes, arborele nu va creste in inaltime*/

pag = insereaza(pag, r->e[1].cheie, &r->e[1]);

free(r); //se sterge pagina scindata, intrucat nodul a fost inserat intr-o alta pagina

}

}

return pag;

}

void afisare(Pagina *arbore, int nivel)

{

int i;

if (!arbore)

return;

afisare(arbore->p0, nivel + 1);

for (i = 1; i <= arbore->m; i++)

afisare(arbore->e[i].p, nivel + 1);

printf("Nivel %d: ", nivel);

for (i = 1; i <= arbore->m; i++)

printf("%d ", arbore->e[i].cheie);

printf("\n");

}

int sumaDimensiuniPagini(Pagina *arbore,int suma)

{

int i;

if(arbore)

{

suma=suma+arbore->m;

suma=sumaDimensiuniPagini(arbore->p0,suma);

for(i=1;i<=arbore->m;i++)

suma=sumaDimensiuniPagini(arbore->e[i].p,suma);

}

return suma;

}

float dimensiuneMediePagina(Pagina *arbore)

{

if(0==numarPagini(arbore,0))

return 0;

return (float)sumaDimensiuniPagini(arbore,0)/numarPagini(arbore,0);

}

int numarPagini(Pagina *arbore,int count)

{

int i;

if(arbore){

count++;

count=numarPagini(arbore->p0,count);

for(i=1;i<=arbore->m;i++)

count=numarPagini(arbore->e[i].p,count);

}

return count;

}

int numarPaginiNivel(Pagina *arbore,int count,int nivelCurent,int nivelCautat)

{

int i;

if(arbore&&(nivelCautat==nivelCurent))

{

count++;

}

if(arbore)

{

count=numarPaginiNivel(arbore->p0,count,nivelCurent+1,nivelCautat);

for(i=1;i<=arbore->m;i++)

count=numarPaginiNivel(arbore->e[i].p,count,nivelCurent+1,nivelCautat);

}

return count;

}

int inaltimeArbore(Pagina* arbore,int nivel)

{

int i;

if(arbore)

{

nivel++;

nivel=inaltimeArbore(arbore->p0,nivel);

}

return nivel;

}

int cautare(Pagina *pag, TipCheie x)

{

/*Cauta cheia x in arbore. Returneaza 1 daca cheia exista, 0 daca nu exista.*/

int s, d, mij;

if (pag == NULL)

return 0;

s = 1;

d = pag->m;

while (s <= d) //cautare binara

{

mij = (s + d) / 2;

if (x == pag->e[mij].cheie)

return 1;

if (x < pag->e[mij].cheie)

d = mij - 1;

else

s = mij + 1;

}

if (d == 0)

return cautare(pag->p0, x);

return cautare(pag->e[d].p, x);

}

void vecinStang(Pagina *pag, Pagina *st, Pagina *r, int d)

{

int i;

if (st->m == N) //daca pagina din stanga are fix N elemente => contopire

{

st->e[N + 1] = pag->e[d];

st->e[N + 1].p = r->p0;

st->m = NN;

for (i = N + 2; i <= NN; i++)

st->e[i] = r->e[i - N - 1];

for (i = d; i < pag->m; i++)

pag->e[i] = pag->e[i + 1];

pag->m--;

free(r);

}

else //imprumut

{

r->m = N;

for (i = N; i > 1; i--)

r->e[i] = r->e[i - 1];

r->e[1] = pag->e[d];

r->e[1].p = r->p0;

r->p0 = st->e[st->m].p;

pag->e[d] = st->e[st->m];

pag->e[d].p = r;

st->m--;

}

}

void vecinDrept(Pagina *pag, Pagina *dr, Pagina *r, int d)

{

int i;

r->e[N] = pag->e[d + 1];

r->e[N].p = dr->p0;

r->m = N;

if (dr->m == N) //daca pagina din dreapta are fix N elemente => contopire

{

r->m = NN;

for (i = N + 1; i <= NN; i++)

r->e[i] = dr->e[i - N];

for (i = 1; i < pag->m; i++)

pag->e[i] = pag->e[i + 1];

pag->m--;

free(dr);

}

else //contopire

{

pag->e[d + 1] = dr->e[1];

pag->e[d + 1].p = dr;

dr->p0 = dr->e[1].p;

for (i = 1; i < dr->m; i++)

dr->e[i] = dr->e[i + 1];

dr->m--;

}

}

Pagina* suprima(Pagina *pag, TipCheie x, Nod *nod)

{

int i, s, d, mij;

Pagina *q, *r;

//daca nu exista cheia in arbore

if (pag == NULL || pag->m == 0)

return NULL;

s = 1;

d = pag->m;

while (s <= d) //cautare binara

{

mij = (s + d) / 2;

if (x == pag->e[mij].cheie)

break;

if (x < pag->e[mij].cheie)

d = mij - 1;

else

s = mij + 1;

}

/*se suprima cu ajutorul nodului, cu cheie maxima,

mai mica decat cheia nodului curent*/

if (x == pag->e[mij].cheie)

{

if (pag->p0 == NULL) //pagina curenta este pagina terminala

{

/*daca se elimina un nod dintr-o pagina neterminala,

se schimba continutul nodurilor, dar se pastreaza legatura*/

if (nod)

{

q = nod->p;

*nod = pag->e[pag->m];

nod->p = q;

}

for (i = mij; i < pag->m; i++)

pag->e[i] = pag->e[i + 1];

pag->m--;

//pagina terminala curenta s-a golit => arborele scade in inaltime

//posibil doar pentru N == 1

for (q = pag; pag && pag->m == 0; free(q), q = pag)

pag = pag->p0;

return pag;

}

/*dupa mutarea cheii intr-o pagina terminala,

se trece la eliminarea ei, prin repetarea pasului curent;

se presupune ca cheia de sters este mai mica cu o unitate*/

return suprima(pag, x - 1, &pag->e[mij]);

}

if (d == 0)

q = pag->p0;

else

q = pag->e[d].p;

r = suprima(q, x, nod); //se incearca eliminarea cheii din subarborele corespunzator

//conditia (r == NULL) garanteaza ca este pagina terminala

/*daca nu exista cheia aleasa sa inlocuiasca cheia de sters

se repeta pasul de stergere folosind cheia cu cea mai mare valoare*/

if (r == NULL)

{

if (nod)

return suprima(pag, pag->e[d].cheie, nod);

else //daca nu exista cheia in subarbore

return pag;

}

if (r->m < N) //subdepasire => imprumut sau contopire

{

Pagina *st, *dr;

if (d == 1)

st = pag->p0;

else

st = pag->e[d - 1].p;

dr = pag->e[d + 1].p;

if (r == pag->p0) //cel mai din stanga nod

vecinDrept(pag, dr, r, d);

else if (d == pag->m) //cel mai din dreapta nod

vecinStang(pag, st, r, d);

else //are 2 vecini

{

/*

se imprumuta de la vecinul cu nr maxim de noduri in pagina sau se contopesc 2 pagini;

cum nu pot exista simultan 2 pagini cu mai putin de N elemente =>

oricare pagina poate fi aleasa pentru contopire, daca este cazul

*/

//se imprumuta de la vecinul drept

if (dr->m > st->m)

vecinDrept(pag, dr, r, d);

//se imprumuta (sau contopeste) de la (cu) vecinul stang

else

vecinStang(pag, st, r, d);

}

}

//radacina subarborelui curent s-a golit => arborele scade in inaltime

for (q = pag; pag && pag->m == 0; free(q), q = pag)

pag = pag->p0;

return pag;

}

main.c

#include <stdio.h>

#include <stdlib.h>

#include "arborib.h"

Pagina *radacina;

int main()

{

int i, n = 18;

radacina = NULL;

for (i = 1; i <= n; i++)

radacina = insereaza(radacina, i, NULL);

printf("Arborele-B initial:\n");

afisare(radacina, 1);

printf("\n\n");

printf("\nNumar pagini: %d \n",numarPagini(radacina,0));

printf("\nNumar pagini pe nivelul 2: %d\n",numarPaginiNivel(radacina,0,1,2));

printf("\nInaltime arbore: %d\n",inaltimeArbore(radacina,0));

for (i = 1; i <= n; i++)

{

printf("Dupa stergerea lui %d:\n", i);

radacina = suprima(radacina, i, NULL);

printf("\nInaltime arbore: %d\n",inaltimeArbore(radacina,0));

afisare(radacina, 1);

printf("\n\n");

}

return 0;

}