arvores 2-3: arvores B de ordem 3 cada n o tem no m aximo ...noemi/eda-19.1/lab_arvB.pdf · Laborat...

Preview:

Citation preview

Laboratorio/Trabalho: Implementacao de arvores 2-3

arvores 2-3: arvores B de ordem 3

cada no tem no maximo 2 chaves e no mınimo 1 chave

Exemplo de arvore 2-3

200 600

100 150 300 400 700 740

50 12070 140 160 180 220 280 320 360 500 550 620 630 710 720 800 850

arvore 2-3 - implementacao

struct smapa

{

int kp, kg; /* chaves: kp<kg, se kg existir. Se kg=-1,

significa que ele n~ao existe. */

Mapa *pai;

Mapa *esq;

Mapa *meio;

Mapa *dir;

};

arvore 2-3 - implementacao - ideia insercao

se tem espaco no no, coloca chave nele

pode ser necessario “empurrar” a chave existente para a direita

caso contrario, quebra (overflowquebra) em dois

valor mediano e ponteiro para novo no retornados na recursao

arvore 2-3 - implementacao

int insere2 (Mapa* m, int chave, int* valorainserir, Mapa** novofilho) {

int inseriraqui = 0; /* indica se deve inserir neste no */

if (m==NULL) {

printf("erro! subarvore nula! \n"); exit (1);

}

if (m->esq != NULL) {

if (chave < m->kp) {

...

}

else if (((m->kg != -1) && (chave < m->kg)) || (m->kg == -1)) {

...

}

else { /* chave > m->kg */

...

}

}

else { /* este no e folha, tem que inserir nele de qq jeito */

*valorainserir = chave;

inseriraqui = 1;

*novofilho = NULL;

}

if (!inseriraqui) return 0; /* inserc~ao ja esta completa */

...

arvore 2-3 - implementacao

int insere2 (Mapa* m, int chave, int* valorainserir, Mapa** novofilho) {

int inseriraqui = 0; /* indica se deve inserir neste no */

if (m==NULL) {

printf("erro! subarvore nula! \n"); exit (1);

}

if (m->esq != NULL) { /* n~ao e folha, so insere neste no se subir um valor */

if (chave < m->kp) {

inseriraqui = insere2(m->esq, chave, valorainserir, novofilho);

}

else if (((m->kg != -1) && (chave < m->kg)) || (m->kg == -1)) {

/* ou esta entre as duas chaves ou so tem uma chave no no */

inseriraqui = insere2(m->meio, chave, valorainserir, novofilho);

}

else { /* chave > m->kg */

inseriraqui = insere2(m->dir, chave, valorainserir, novofilho);

}

}

else { /* este no e folha, tem que inserir nele de qq jeito */

*valorainserir = chave;

inseriraqui = 1;

*novofilho = NULL;

}

if (!inseriraqui) return 0; /* inserc~ao ja esta completa */

...

arvore 2-3 - implementacao

int insere2 (Mapa* m, int chave, int* valorainserir, Mapa** novofilho) {

int inseriraqui = 0; /* indica se deve inserir neste no */

...

if (!inseriraqui) return 0; /* inserc~ao ja esta completa */

if (m->kg==-1) {

/* tem espaco no no */

/* COMPLETAR */

return 0; /* como havia espaco, n~ao sobem valores a serem inseridos */

}

*novofilho = overflowQuebra (m, valorainserir, *novofilho);

return 1; /* quando ha quebra sempre sobe a mediana para nova inserc~ao */

}

Exemplo de arvore 2-3

200 600

100 150 300 400 700 740

50 12070 140 160 180 220 280 320 360 500 550 620 630 710 720 800 850

inserir 210

220 280210

Exemplo de arvore 2-3

200 600

100 300 400 700 740

320 360 500 550

220

280

210

-1

-1… …novo

valorainserir

Exemplo de arvore 2-3

220

200 600

100 300 400 700 740

320 360 500 550

220

280

210

-1

-1… …novo

200 600

100300

400 700 740

320 360 500 550

220

280

210

-1

-1… …

-1-1

novo

Exemplo de arvore 2-3

200 600

100300

400 700 740

320 360 500 550

220

280

210

-1

-1… …

-1-1

novo

200 600

100

300

400 700 740

320 360 500 550

220

280

210

-1

-1… …

-1-1

novo-1 -1

Exemplo de arvore 2-3

200 600

100

300

400 700 740

320 360 500 550

220

280

210

-1

-1… …

-1-1

novo-1 -1

200 600

100

300

400 700 740

320 360 500 550

220

280

210

-1

-1… …

-1-1

-1 -1

-1

arvore 2-3 - implementacao

static Mapa* overflowQuebra (Mapa *m, int *valorainserir, Mapa* novofilho) {

Mapa* novo;

novo = (Mapa*) malloc(sizeof(struct smapa));

...

if (*valorainserir < m->kp) {

/* FEITO */

else if (*valorainserir < m->kg) {

/* completar */

}

else {

/* completar */

}

return novo;

}

arvore 2-3 - implementacao

static Mapa* overflowQuebra (Mapa *m, int *valorainserir, Mapa* novofilho) {

Mapa* novo;

novo = (Mapa*) malloc(sizeof(struct smapa));

if (*valorainserir < m->kp) {

novo->esq = novofilho;

if (novo->esq) novo->esq->pai = novo;

novo->kp = *valorainserir;

novo->meio = m->esq;

if (novo->meio) novo->meio->pai = novo;

novo->kg = -1;

novo->dir = NULL;

*valorainserir = m->kp;

m->esq = m->meio;

m->kp = m->kg;

}

else if (*valorainserir < m->kg) {

/* completar */

}

else {

/* completar */

}

m->meio = m->dir;

m->kg = -1;

m->dir = NULL;

return novo;

}

arvore 2-3 - implementacao

static Mapa* overflowQuebra (Mapa *m, int *valorainserir, Mapa* novofilho) {

Mapa* novo;

novo = (Mapa*) malloc(sizeof(struct smapa));

if (*valorainserir < m->kp) {

novo->esq = novofilho;

if (novo->esq) novo->esq->pai = novo;

novo->kp = *valorainserir; novo->meio = m->esq;

if (novo->meio) novo->meio->pai = novo;

novo->kg = -1; novo->dir = NULL;

*valorainserir = m->kp;

m->esq = m->meio; m->kp = m->kg;

}

else if (*valorainserir < m->kg) { /* completar */ }

else { /* completar */ }

m->meio = m->dir;

m->kg = -1;

m->dir = NULL;

return novo;

}

arvore 2-3 - implementacao

int insere2 (Mapa* m, int chave, int* valorainserir, Mapa** novofilho);

Mapa* insere (Mapa* m, int chave) {

int valorquesubiu; Mapa* novofilho; Mapa* novaraiz;

if (m==NULL) {

m = novoNo (chave);

m->pai = novoNo (-1);

}

else {

if (insere2 (m, chave, &valorquesubiu, &novofilho)) {

/* cria nova raiz */

novaraiz = novoNo (valorquesubiu);

novaraiz->pai = m->pai;

novaraiz->esq = novofilho;

novaraiz->esq->pai = novaraiz;

novaraiz->meio = m;

novaraiz->meio->pai = novaraiz;

m = novaraiz;

}

}

return m;

}

arvore 2-3 - insercao

C -1

T1 T2

V C

T1 T2

V

novofilho

novofilho

m m

arvore 2-3 - insercao

c1 c2

T1 T2

m

X

T2 ou T3“acabaram” -sobroufilhoqueficou

T3

c1 -1

T1 filhoqueficou

m

arvore 2-3 - insercao

c1 c2

T1 T2

v

novofilho

T3

v -1

T1 T2

novo novofilho

T3

c2 -1

c1

novofilho

m m

arvore 2-3 - insercao

c1 c2

T1 T2v

novofilho

T3

c1 -1

T1 T2

novo novofilho

T3

c2 -1

v

novofilho

m m

arvore 2-3 - insercao

c1 c2

T1 T2v

novofilho

T3

c1 -1

T1 T2

novo novofilho

T3

v -1

c2

novofilho

m m

arvore 2-3 - retirada

arvore sempre deve ficar cheia

arvore 2-3 - retirada – casos simples

c1 c2

T1 T2 T3

m

X c2 -1

T1ouT2

T3

m

T1 ou T2 “acabaram”

c1 c2

T1 T2

m

X

T2 ou T3“acabaram” -sobroufilhoqueficou

T3

c1 -1

T1 filhoqueficou

m

arvore 2-3 - retirada – caso combinacao

c1 -1

T1 T2

i1 -1

T4

irmão

T3

m

X

T1 ou T2 “acabaram” -sobroufilhoqueficou

p1 ?

m->pai

c1 -1

T1 filhoqueficou

p1 i1

T4

irmão

T3

m

resultado recursão:

RETIRAMENOR Xp1 ?

m->pai

arvore 2-3 - retirada – caso redistribuicao

c1 -1

T1 T2

i1 i2

T4

irmão

T3

m

X

T1 ou T2 “acabaram” -sobroufilhoqueficou

p1 ?

m->pai

T5

p1 -1

T3

i2 -1

T5

irmão

T4

m

i1 ?

m->pai

filhoqueficou

resultado recursão:OK

arvore 2-3 - retirada

tresultret retirarec (Mapa *m, int chave) {

..

if (m==NULL) { printf("erro! subarvore nula! \n"); exit (1); }

if (m->esq != NULL) { /* n~ao e folha */

if (chave < m->kp) {

res = retirarec (m->esq, chave);

}

else if (m->kp == chave) { /* achou - troca por succ */

m->kp = maisaesquerda (m->meio);

res = retirarec (m->meio, m->kp);

}

else if (((m->kg != -1) && (chave < m->kg)) || (m->kg == -1)) {

/* ou esta entre as duas chaves ou so tem uma chave no no */

res = retirarec(m->meio, chave);

}

else if (m->kg == chave) { /* achou - troca por succ */

m->kg = maisaesquerda (m->dir);

res = retirarec (m->dir, m->kg);

}

else { /* chave > m->kg */

res = retirarec(m->dir, chave);

}

if (res==OK) return OK;

}

else { /* este no e folha, chave tem que estar nele de qq jeito */

if (chave==m->kp) res = RETIRA_MENOR;

else if (chave == m->kg) res = RETIRA_MAIOR;

else /* chave n~ao esta na arvore!!! */

return OK;

}

/* retirada */

...

return res;

}

arvore 2-3 - retirada

tresultret retirarec (Mapa *m, int chave) {

...

/* retirada */

/* pode ser porque estamos em uma folha ou porque "caiu" uma das chaves */

if (res == RETIRA_MAIOR) { /* caso mais simples */

preenche (m, m->esq, m->kp, m->meio?m->meio:m->dir, -1, NULL);

return OK;

}

/* RETIRAMENOR */

if (m->kg != -1) {

/* ainda vai ficar um no no, tb simples */

}

/* RETIRAMENOR: essa e a unica chave! combinar ou distribuir */

minhapos = minhaposnopai (m->pai, m);

/* se ainda tiver algum filho pega-lo para passar para outro */

filhoqueficou = m->esq?m->esq:m->meio;

if (minhapos == ESQ) {

irmao = m->pai->meio;

if (irmao->kg == -1) { /* combinar */

...

}

else ...

}

else ...

...

return res;

}