• Nenhum resultado encontrado

INF 1010 Estruturas de Dados Avançadas

N/A
N/A
Protected

Academic year: 2021

Share "INF 1010 Estruturas de Dados Avançadas"

Copied!
52
0
0

Texto

(1)

! !

INF 1010

Estruturas de Dados Avançadas

(2)

Árvores

(3)

Balanceamento de

Árvores Binárias de Busca

Motivação:

busca em O(log(n))

Estratégia:

diminuir a diferença de altura entre

a sub-árvore à esquerda e

a sub-árvore à direita

de cada nó

(4)

Árvore binária de busca construída de tal modo que

em todos seus nós, a altura de sua sub-árvore à

direita difere da altura da sub-árvore à esquerda de

no máximo 1 unidade

(5)

Fator de balanceamento

Fator de balanceamento de um nó

fb = hd – he

onde

he = altura da sub-árvore à esquerda

hd = altura da sub-árvore à direita

struct

&_avl&{&

&&&&int

&chave;&

&&&&int

&fb;&

/*fator&de&balanceamento*/

&

&&&&struct

&_avl&*pai;&

&&&&struct

&_avl&*esq;&

&&&&struct

&_avl&*dir;&

};&

(6)

Árvore AVL – desequilíbrio (caso 1a)

10 8 6 4 2

árvore balanceada (equilibrada)

0 0 0 0 -1 10 8 6 4 2 1

desequilíbrio após inserir 1

0 -1 0 -1 -2 0 10 8 6 4 2 3

desequilíbrio após inserir 3

1 0

-1

-2

0

(7)

Árvore AVL – Caso 1a: rotação à direita

r t m sad nova raiz static&Avl*&rotacao_direita(Avl&*r)&{& &&&&Avl&*pai=r?>pai,&*t=r?>esq,&*m=t?>dir;& &&&&t?>dir&=&r;&&r?>pai&=&t;& &&&&r?>esq&=&m;&&if&(m)&m?>pai&=&r;& &&&&t?>pai&=&pai;&& &&&&if&(pai)&{& &&&&&&&&if&(pai?>dir&==&r)&pai?>dir&=&t;& &&&&&&&&else&pai?>esq&=&t;& &&&&}& &&&&t?>fb&=&r?>fb&=&0;&& &&&&return&t;& }& -1 -2 h+1 h h t m r sad h h h+1 0 0 h+1

(8)

a c b 0 -1 -2 a c b 0 0 0

Uma rotação à direita !

(9)

Caso 1a - Exemplo de rotação à direita

10 8 6 4 2 1 0 -1 0 -1 -2 0 10 8 6 4 2 1 0 -1 0 0 0 0 10 8 6 4 2

árvore balanceada (equilibrada)

0 0

0 0

-1

(10)

Árvore AVL – desequilíbrio (caso 1b)

10 8

4

12 árvore balanceada (equilibrada)

0

0 0

1

9 0

desequilíbrio após inserir 11

10 8 4 12 -1 0 2 1 11 0 9 0

desequilíbrio após inserir 13

10 8 4 12 1 0 2 1 13 0 9 0

(11)

t m r sae r t m

sae nova raiz

Árvore AVL – Caso 1b: rotação à esquerda

static&Avl*&rotacao_esquerda(Avl&*r)&{& &&&&Avl&*pai=r?>pai,&*t=r?>dir,&*m=t?>esq;& &&&&t?>esq&=&r;&&&r?>pai&=&t;& &&&&r?>dir&=&m;&&&if&(m)&m?>pai&=&r;& &&&&t?>pai&=&pai;&if&(pai)&{& &&&&&&&&if&(pai?>dir&==&r)&pai?>dir&=&t;& &&&&&&&&else&&&&&&&&&&&&&&&pai?>esq&=&t;& &&&&}& &&&&t?>fb&=&r?>fb&=&0;& &&&&return&t;& }& 1 2 h+1 h h h+1 h h 0 0 h+1

(12)

Caso 1b - Exemplo de rotação à esquerda

a c b 0 1 2 a c b 0 0 0

(13)

Árvore AVL – Casos simples: fb com

mesmo sinal

r t m sad nova raiz t m r sad -1 -2 h+1 h h h h h+1 0 0 h+1 r t m

sae nova raiz

t m r sae 1 2 h+1 h h h+1 h h 0 0 h+1

1a

1b

(14)

a c b 0 1 -2

Exemplo: caso em que rotação simples não resolve

r

t

m

c a b a c b 0 1 -2

r

t

m

Não resolve!

(15)

a c b

0 0

0

Uma rotação à

direita

na sub-árvore à

direita

c a b 0 -1 2 a c b

Caso 2a - Balanceamento com rotação dupla

(16)

Caso 2a – Rotação direita-esquerda

2 r t T4 -1 T1 s T2 T3 r t T4 T1 s T2 T3 r t T4 T1 s T2 T3 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *t = r->dir, *s = t->esq;

Avl *T2 = s->esq, *T3 = s->dir;

s->esq = r; s->dir = t; r->dir = T2; t->esq = T3; r->fb = (s->fb==1) ? -1 : 0; t->fb = (s->fb==-1) ? 1 : 0; s->fb = 0; return s; } ( Explicação a seguir )

(17)

Caso 2a.1 – Rotação direita-esquerda

2 r t T4 -1 T1 s T2 T3 1 r t T4 T1 s T2 T3 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *t = r->dir, *s = t->esq;

Avl *T2 = s->esq, *T3 = s->dir;

s->esq = r; s->dir = t; r->dir = T2; t->esq = T3; r->fb = (s->fb==1) ? -1 : 0; t->fb = (s->fb==-1) ? 1 : 0; s->fb = 0; return s; } 0 0 -1 h h-1 h h

(18)

Caso 2a.2 – Rotação direita-esquerda

2 r t T4 -1 T1 s T2 T3 -1 r t T4 T1 s T2 T3 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *t = r->dir, *s = t->esq;

Avl *T2 = s->esq, *T3 = s->dir;

s->esq = r; s->dir = t; r->dir = T2; t->esq = T3; r->fb = (s->fb==1) ? -1 : 0; t->fb = (s->fb==-1) ? 1 : 0; s->fb = 0; return s; } 1 0 0 h h h-1 h

(19)

Caso 2a.3 – Rotação direita-esquerda

2 r t T4 -1 T1 s T2 T3 0 r t T4 T1 s T2 T3 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *t = r->dir, *s = t->esq;

Avl *T2 = s->esq, *T3 = s->dir;

s->esq = r; s->dir = t; r->dir = T2; t->esq = T3; r->fb = (s->fb==1) ? -1 : 0; t->fb = (s->fb==-1) ? 1 : 0; s->fb = 0; return s; } 0 0 0 h h h h

(20)

a c b

0 0

0

Uma rotação à

esquerda

na sub-árvore à

esquerda

a c b 0 1 -2 a c b

Caso 2b - Balanceamento com rotação dupla

(21)

Caso 2b – Rotação esquerda-direita

-2 r p T1 1 T4 q T3 T2 p r T4 T1 q T2 T3 r p T1 T4 q T3 T2 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *p = r->esq, *q = p->dir;

Avl *T2 = q->esq, *T3 = q->dir;

q->esq = p; q->dir = r; p->dir = T2; r->esq = T3; p->fb = (q->fb==1) ? -1 : 0; r->fb = (q->fb==-1) ? 1 : 0; q->fb = 0; return q; } ( Explicação a seguir )

(22)

Caso 2b.1 – Rotação esquerda-direita

p r T4 T1 q T2 T3 0 0 -1 h h-1 h h -2 r p T1 1 T4 q T3 T2 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *p = r->esq, *q = p->dir;

Avl *T2 = q->esq, *T3 = q->dir;

q->esq = p; q->dir = r; p->dir = T2; r->esq = T3; p->fb = (q->fb==1) ? -1 : 0; r->fb = (q->fb==-1) ? 1 : 0; q->fb = 0; return s; } 1

(23)

Caso 2b.2 – Rotação esquerda-direita

p r T4 T1 q T2 T3 1 0 0 h h h-1 h -2 r p T1 1 T4 q T3 T2 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *p = r->esq, *q = p->dir;

Avl *T2 = q->esq, *T3 = q->dir;

q->esq = p; q->dir = r; p->dir = T2; r->esq = T3; p->fb = (q->fb==1) ? -1 : 0; r->fb = (q->fb==-1) ? 1 : 0; q->fb = 0; return s; } -1

(24)

Caso 2b.3 – Rotação esquerda-direita

p r T4 T1 q T2 T3 0 0 0 h h h h -2 r p T1 1 T4 q T3 T2 Avl* avl_rotacao_direita_esquerda(Avl *r) { Avl *p = r->esq, *q = p->dir;

Avl *T2 = q->esq, *T3 = q->dir;

q->esq = p; q->dir = r; p->dir = T2; r->esq = T3; p->fb = (q->fb==1) ? -1 : 0; r->fb = (q->fb==-1) ? 1 : 0; q->fb = 0; return s; } 0

(25)
(26)

Inserção à esquerda

r -1 desbalanceado r -2 r 0 balanceado (mas pode ter desbalanceado acima) r -1 r 1 balanceado r 0 antes da inserção após a inserção r -2 t 1 r -2 t -1 rotação direita

(27)

static Avl* avl_insere2(Avl* r,int chave, int* flag) { if (r==NULL) {

r = (Avl*) malloc(sizeof(Avl)); r->esq = r->dir = NULL;

r->chave = chave; r->fb = 0;

*flag = 1; }

else if (r->chave > chave) {

r->esq = avl_insere2 (r->esq, chave, flag); if (*flag) …

}

else if (r->chave < chave) {

r->dir = avl_insere2 (r->dir, chave, flag); if (*flag) …

}

return r; }

Avl* avl_insere(Avl* r, int chave) { int flag=0;

return avl_insere2 (r,chave,&flag); }

if (*flag) { /* r cresceu à esquerda (ou seja, he aumentou)*/ switch(r->fb) { /* análise do fator de balanceamento de r */

case 1: /* antes: hd>he xxx depois: hd=he pois he aumentou */ r->fb = 0; *flag = 0; break;

case 0: /* antes: hd=he xxx depois: hd<he pois he aumentou */ r->fb = -1; break;

case -1: /* antes: hd<he xxx depois: hd-he=-2 pois he aumentou */ if (r->esq->fb == -1) r = avl_rotacao_direita(r);

else r = avl_rotacao_esquerda_direita(r); *flag = 0; break;

} }

(28)

Animação de Árvores AVL

(29)

Remoções

Problemas

semelhantes aos das inserções, ou seja,

pode ocorrer desbalanceamento

Análise de casos:

Caso 1:

o nó removido é uma folha, ou

o nó removido possui apenas 1 descendente

Caso 2:

(30)

Exemplo: Remove 4

5 3 8 2 4 1 7 10 9 11 6 5 3 8 2 1 7 10 9 11 6 5 3 8 2 1 7 10 9 11 6 rotação à direita

(31)

Exemplo: Remove 8

5 3 8 2 1 7 10 9 11 6 5 3 7 2 1 6 10 9 11

(32)

Exemplo: Remove 6

5 3 7 2 1 6 10 9 11 5 3 7 2 1 10 9 11 rotação à esquerda 5 3 7 2 1 10 9 11

(33)

Problemas com as Árvores AVL

Problema:

Nem sempre uma ÚNICA rotação

(simples ou dupla) resolve

o problema de desbalanceamento dos nós

Há casos em que O(log n) rotações são

necessárias para tornar a árvore balanceada

Exemplo (a seguir):

(34)

rotação dupla

Múltiplas Rotações na Árvore AVL

5 4 9 3 1 8 11 10 12 7 2 6 5 9 3 1 8 11 10 12 7 2 6 5 9 3 1 8 11 10 12 7 2 6 5 9 3 1 8 11 10 12 7 2 6 rotação dupla 5 9 3 1 8 11 10 12 7 2 6

(35)

Esboço do algoritmo de remoção

• 

Pesquise o nó que contém a chave procurada,

aplicando recursivamente o algoritmo de remoção

• 

Quando achar o nó

faça a remoção

(semelhante à remoção em árvore de busca binária)

analise o balanceamento

Se o nó estiver desbalanceado ( |fb| >1 ),

faça as devidas rotações

• 

Recursivamente, reporte uma mudança na altura de um nó

ao seu pai para que ele faça as devidas correções

(36)

Esboço do algoritmo de remoção

• 

Pontos adicionais da remoção

(que não ocorrem na inserção)

É necessário tratar todos os casos possíveis

de altura nas rotações

É necessário analisar quando

uma sub-árvore muda de altura

(37)

Casos de rotação à esquerda (a s.a.e. perdeu altura)

2 r t T4 1 T1 m rotação à esquerda 0 r t T4 0 T1 m 2 r t T4 0 T1 m rotação à esquerda 1 r t T4 -1 T1 m

static Avl* rot_esquerda(Avl *r) { Avl *t=r->dir, *m=t->esq;

t->esq = r; r->dir = m; if (t->fb==1) { t->fb = 0; r->fb = 0; } else { t->fb = -1; r->fb= 1; } return t; } 2 r t T4 -1 T1 s T2 T3 rotação dupla

(38)

Rotação dupla direita-esquerda (fb=2)

2 r t T4 -1 T1 s T2 T3 0 2 r t T4 -1 T1 s T2 T3 -1 2 r t T4 -1 T1 s T2 T3 1 r t T4 T1 s T2 T3 0 1 0 r t T4 T1 s T2 T3 0 0 -1 r t T4 T1 s T2 T3 0 0 0

(39)

static Avl* rotacao_direita_esquerda(Avl *r) { Avl *t=r->dir,*s=t->esq,*T2=s->esq,*T3=s->dir; s->esq = r; s->dir = t; r->dir = T2; t->esq = T3; switch (s->fb){ case -1: r->fb = s->fb = 0; t->fb = 1; break; case 0: r->fb = s->fb = t->fb = 0; break; case 1: r->fb = -1; s->fb = t->fb = 0; break; } return s; }

(40)

Casos de rotação à direita (a s.a.d. perdeu altura)

-2 r t T1 -1 T4 m rotação à direita 0 r t T1 0 T4 m -2 r t T1 0 T4 m rotação à direita -1 r t T1 1 T4 m

static Avl* rot_direita(Avl *r) { Avl *t=r->esq, *m=t->dir;

t->dir = r; r->esq = m; if (t->fb == -1) { t->fb = 0; r->fb = 0; } else { t->fb = 1; r->fb = -1; } return t; } -2 r p T1 1 T4 q T3 T2 rotação dupla

(41)

Rotação dupla esquerda-direita (fb=-2)

-2 r p T1 1 T4 q T3 T2 0 -2 r p T1 1 T4 q T3 T2 -1 -2 r p T1 1 T4 q T3 T2 1 p r T4 T1 q T2 T3 0 1 0 p r T4 T1 q T2 T3 0 0 -1 p r T4 T1 q T2 T3 0 0 0

(42)

static Avl* rotacao_esquerda_direita(Avl *r) { Avl *p=r->esq,*q=p->dir,*T2=q->esq,*T3=q->dir; q->esq = p; q->dir = r; p->dir = T2; r->esq = T3; switch (q->fb){ case -1: r->fb = 1; q->fb = p->fb = 0; break; case 0: r->fb = q->fb = p->fb = 0; break; case 1: r->fb = q->fb = 0; p->fb = -1; break; } return q; }

(43)

static Avl* avl_remove2(Avl *r, int chave, int *delta_h) { if (!r) return NULL;

else if (chave < r->chave) {

r->esq = avl_remove2(r->esq, chave, delta_h); r->fb -= *delta_h;

if (r->fb == 2) {

if (r->dir->fb == 1) { r=rotacao_esquerda(r); *delta_h =-1; } else if (r->dir->fb == 0) { r=rotacao_esquerda(r); *delta_h = 0; } else if (r->dir->fb == -1)

{ r=rotacao_direita_esquerda(r); *delta_h=-1; } }

else *delta_h=((r->fb==1) ? 0 : -1); /*a sad mantém a altura do nó*/ }

else if (chave > r->chave) { /* caso simétrico */ }

else { /* achou o nó para remover – remoção semelhante à abb */ if (r->esq == NULL && r->dir == NULL) /* nó folha */

{ free(r); *delta_h = -1; r = NULL; }

else if (r->dir == NULL) /* só um filho, à esquerda */ …

}

return r; }

Avl* avl_remove(Avl *r, int chave) { int delta_h = 0;

(44)

Relação entre altura e número de nós numa AVL

h-1

h-2 h-2

0 0

h-1

h-2

h

Então, a altura de uma das sub-árvores é, no mínimo, h-1 e

a altura da outra é, no mínimo, h-2.

Seja N(h) o número mínimo de nós de uma AVL de altura h.

1 ) 2 ( ) 1 ( ) (h = N h− + N h− + N

[

N(h)+1

] [

= N(h−1)+1

] [

+ N(h−2)+1

]

[

N(h)+1

]

= são números de Fibonacci

3 2 5 1 5 1 1 ) ( + ! ! " # $ $ % & + ≈ + h h N

( )

)

log

44

.

1

n

h ≈

(45)

TAD avl.h

typedef struct _avl Avl;

Avl* avl_create(int (*pcomp)(const void*,const void*), void (*pfree)(void*)); Avl* avl_free(Avl* tree);

void avl_insert(Avl* tree, void* pinfo); void avl_remove (Avl* tree, void* pinfo); void* avl_first (Avl* tree);

(46)

TAD avl.c (1)

typedef struct _avl_node AvlNode; struct _avl_node {

void* info;

int fb; /* balance factor = hr - hl */ AvlNode* parent; AvlNode* left; AvlNode* right; }; struct _avl { AvlNode* root; AvlNode* current;

int (*pcompare)(const void*,const void*); void (*pfree)(void*);

(47)

TAD avl.c (2)

static AvlNode* rotate_right(AvlNode *r) {

AvlNode *parent=r->parent, *t=r->left, *m=t->right; t->right = r; r->parent = t;

r->left = m; if (m) m->parent = r; t->parent = parent; if (parent) {

if (parent->right == r) parent->right = t; else parent->left = t; } if (t->fb==-1) { t->fb = 0; r->fb = 0; } else { t->fb = 1; r->fb =-1; } return t; }

(48)

TAD avl.c (3)

static AvlNode* rotate_right_left(AvlNode *r) {

AvlNode *parent=r->parent,*t=r->right,*s=t->left,*T2=s->left,*T3=s->right; s->left = r; r->parent = s;

s->right = t; t->parent = s;

r->right = T2; if (T2) T2->parent = r; t->left = T3; if (T3) T3->parent = t; s->parent = parent; if (parent) {

if (parent->right == r) parent->right = s; else parent->left = s; } switch (s->fb){ case -1: r->fb=s->fb=0; t->fb=1; break; case 0: r->fb=s->fb=t->fb=0; break; case 1: r->fb=-1; s->fb=t->fb=0; break; } return s; }

(49)

TAD avl.c (4)

static AvlNode* insert(Avl* tree, AvlNode* r, void* info, int* delta_h) { if (r==NULL) {

r = (AvlNode*) malloc(sizeof(AvlNode)); r->left = r->right = r->parent = NULL; r->info = info; r->fb = 0; *delta_h = 1; } else if (tree->pcompare(info,r->info)<0) { r->left = insert(tree,r->left,info,delta_h); if (r->left) r->left->parent = r; if (*delta_h) { switch(r->fb){

case 1: r->fb = 0; *delta_h = 0; break; case 0: r->fb = -1; break; case -1: if (r->left->fb == -1) r = rotate_right(r); else r = rotate_left_right(r); *delta_h = 0; break; } } } else if (tree->pcompare(info,r->info)>0) { ... return r; }

(50)

TAD avl.c (5)

static AvlNode* remove_node(Avl* tree, AvlNode *r, void* info, int *delta_h) { if (!r) return NULL;

else if (tree->pcompare(info,r->info)<0) {

r->left = remove_node(tree,r->left, info, delta_h); if (r->left) r->left->parent=r;

if (*delta_h==-1){ r->fb++;

if (r->fb==2){

switch (r->right->fb){

case 1: { r=rotate_left(r); *delta_h=-1; break; } case 0: { r=rotate_left(r); *delta_h= 0; break; } case -1: { r=rotate_right_left(r); *delta_h=-1; break; } }

} else

*delta_h=(r->fb==1)?0:-1; /* right sub-tree can sustain the node height */ }

}

else if (tree->pcompare(info,r->info)>0) { ...

(51)

TAD avl.c (6)

... }

else { /* found node to be removed */

if (r->left==NULL && r->right==NULL) /* leaf */

{ if (tree->pfree) tree->pfree(r->info); free(r); *delta_h=-1; r = NULL; } else if (r->right == NULL) /* only left child */

{ AvlNode* t = r; r = r->left; if (tree->pfree) tree->pfree(t->info); free(t); *delta_h=-1; }

else if (r->left == NULL) /* only right child */

{ AvlNode* t = r; r = r->right; if (tree->pfree) tree->pfree(t->info); free(t); *delta_h=-1; }

else { /* two children */

AvlNode *r0=r, *successor = r->right; void* info2;

while (successor->left !=NULL) successor = successor->left; info2 = successor->info; r = remove_node(tree,r,info2,delta_h); r0->info = info2; } } return r; }

(52)

TAD avl.c (7)

void* avl_next(Avl *tree) {

if (tree==NULL) return NULL; else {

AvlNode* node = tree->current; if (node==NULL) return NULL;

else if (node->right!=NULL) { /* returns min of right sub-tree */ node=node->right;

while(node->left!=NULL) node=node->left; tree->current=node;

return node->info;

} else { /* returns the nearest ancestor that is larger than its child */ AvlNode* p = node->parent;

while ( p!=NULL && node==p->right ) { node = p; p = p->parent; } tree->current=p; return (p!=NULL)?p->info:NULL; } } }

Referências

Documentos relacionados

Estudo do Meio (Descoberta das inter-relações entre espaços: o contacto entre a terra e o mar.. Exemplo de abordagem Articulação com conteúdos

Professores do 3º Ciclo e do Ensino Secundário da Esc.. Ação e formador Área Destinatários Modalidade e nº horas Calendarização. APRENDIZAGEM ATIVA COM RECURSO ÀS TIC

As árvores onde cada nó que não seja folha numa árvore binária tem sub- árvores esquerda e direita não vazias são conhecidas como árvores estritamente binárias.. apresenta

Embora tenha sido construído e adaptado para o exame dos distúrbios comunicativos em pacientes lesados de hemisfério direito, também pode auxiliar na investigação de seqüelas

VETERANO

res de Tridax procumbens submetidos a diferentes concentrações de 2,4-D, AIB ou ANA acrescidos de BAP.. FIGURA 5 – Peso da matéria seca dos calos formados a partir de segmentos

Gerir uma vila alentejana no século XV: as finanças municipais de Elvas em 1432-1433 FRAGMENTA

4.15 - Superfície de resposta e curva de contorno para a concentração residual de sacarose em função da concentração celular no inóculo e da concentração inicial de sacarose ...69