A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Árvores binárias de pesquisa com balanceamento Algoritmos e Estruturas de Dados II.

Apresentações semelhantes


Apresentação em tema: "Árvores binárias de pesquisa com balanceamento Algoritmos e Estruturas de Dados II."— Transcrição da apresentação:

1 Árvores binárias de pesquisa com balanceamento Algoritmos e Estruturas de Dados II

2 Árvores binárias de pesquisa 2 Pior caso para uma busca é O(n) Ordem de inserção:

3 Árvore Binária Balanceada 3 Uma árvore binária está balanceada se e somente se para todo nó, as alturas de suas duas sub-árvores diferem de no máximo 1. Objetivo: Funções para pesquisar, inserir e retirar eficientes O(lg(n)) Problema: manter árvore completamente balanceada após cada inserção é muito caro

4 Árvore Binária Balanceada 4 Exemplo: Para inserir a chave 1 na árvore à esquerda e manter a árvore completamente balanceada precisamos movimentar todos os nós

5 Árvores Quase Balanceadas 5 Solução intermediária que mantém a árvore quase balanceada, em vez de tentar manter a árvore completamente balanceada Manter a altura da árvore pequena diante de inserções e remoções arbitrárias. Ex: Árvores AA, AVL, Red-Black (ou SBB), Splay, Treap, etc.

6 Árvores SBB 6 Árvore SBB Árvore binária de busca. Os ponteiros à esquerda ou direita podem ser do tipo horizontal ou vertical. Todos os caminhos da raiz até cada nó externo possuem o mesmo número de apontadores verticais Todos os nós, exceto aqueles no último nível, têm dois filhos Não podem existir dois apontadores horizontais sucessivos

7 Árvores SBB – estrutura 7 #define SBB_VERTICAL 0 #define SBB_HORIZONTAL 1 struct sbb { struct registro reg; struct sbb *esq; struct sbb *dir; int esqtipo; int dirtipo; }

8 Pesquisa em árvore SBB 8 Idêntica à pesquisa em uma árvore de busca binária não balanceada Ignoramos o tipo (horizontal ou vertical) dos apontadores

9 Inserção numa árvore SBB 9 A chave a ser inserida é sempre inserida horizontalmente na posição adequada Dependendo da situação anterior à inserção podem aparecer dois apontadores horizontais Transformação local para manter as propriedades da árvore SBB Inserção do 4, 6, 8, 11?

10 Métodos para reorganizar casos onde aparecem dois ponteiros horizontais consecutivos Esquerda-esquerda (e direita-direita) Esquerda-direita (e direita-esquerda) Transformações para manter propriedadas da árvore SBB 10

11 Exemplo de inserção em árvore SBB 11 Inserir chaves 7, 10, 5, 2, 4, 9, 3, 6

12 Transformações para manter propriedadas da árvore SBB - código 12 void ee(struct sbb *ptr) { struct sbb *no = ptr; struct sbb *esq = no->esq; no->esq = esq->dir; esq->dir = no; esq->esqtipo = SBB_VERTICAL; no->esqtipo = SBB_VERTICAL; &ptr = esq; } ptr no esq x x ptr

13 Transformações para manter propriedadas da árvore SBB - código 13 void dd(struct sbb *ptr) { struct sbb *no = ptr; struct sbb *dir = no->dir; no->dir = dir->esq; dir->esq = no; dir->dirtipo = SBB_VERTICAL; no->dirtipo = SBB_VERTICAL; &ptr = dir; } ptr 123 x dir no x

14 Transformações para manter propriedadas da árvore SBB - código 14 void ed(struct sbb *ptr) { struct sbb *no = ptr; struct sbb *esq = no->esq; struct sbb *dir = esq->dir; esq->dir = dir->esq; no->esq = dir->dir; dir->esq = esq; dir->dir = no; esq->dirtipo = SBB_VERTICAL; no->esqtipo = SBB_VERTICAL; &ptr = dir; } ptr no esqdir xy x y ptr

15 Transformações para manter propriedadas da árvore SBB - código 15 void de(struct sbb *ptr) { struct sbb *no = ptr; struct sbb *dir = no->dir; struct sbb *esq = dir->esq; no->dir = esq->dir; dir->esq = esq->dir; esq->esq = no; esq->dir = dir; dir->esqtipo = SBB_VERTICAL; no->dirtipo = SBB_VERTICAL; &ptr = dir; } esq 123 x ptr dir no y ptr x y

16 Inserção em árvores SBB 16 void iinsere(struct registro reg, struct sbb **ptr, int *incli, int *fim) { /* adiciona, pois encontrou uma folha */ if(*ptr == NULL) iinsere_aqui(reg, ptr, incli, fim); /* busca na sub-árvore esquerda */ } else if(reg.chave reg.chave) { iinsere(reg, &(*ptr->esq), &(*ptr->esqtipo), fim); if(*fim) return; if(*ptr->esqtipo == SBB_VERTICAL) { *fim = TRUE; } else if(*ptr->esq->esqtipo == SBB_HORIZONTAL) { ee(ptr); *incli = SBB_HORIZONTAL; } else if(*ptr->esq->dirtipo == SBB_HORIZONTAL) { ed(ptr); *incli = SBB_HORIZONTAL; } /* continua */

17 Inserção em árvores SBB 17 /* busca na sub-árvore direita */ } else if(reg.chave > (*ptr)->reg.chave) { iinsere(reg, &(*ptr->dir), &(*ptr->dirtipo), fim); if(*fim) return; if(*ptr->dirtipo == SBB_VERTICAL) { *fim = TRUE; } else if(*ptr->dir->dirtipo == SBB_HORIZONTAL) { dd(ptr); *incli = SBB_HORIZONTAL; } else if(*ptr->dir->esqtipo == SBB_HORIZONTAL) { de(ptr); *incli = SBB_HORIZONTAL; } /* chave já existe */ } else { printf(erro: chave já está na árvore.\n); *fim = TRUE; }

18 Inserção em árvores SBB 18 void iinsere_aqui(struct registro reg, struct sbb **ptr, int *incli, int *fim) { struct sbb *no = malloc(sizeof(struct sbb)); no->reg = reg; no->esq = NULL; no->dir = NULL; no->esqtipo = SBB_VERTICAL; no->dirtipo = SBB_VERTICAL; *ptr = no; *incli = SBB_HORIZONTAL; *fim = FALSE; }

19 Inserção em árvores SBB 19 void insere(struct registro reg, struct sbb **raiz) { int fim = FALSE; int inclinacao = SBB_VERTICAL; iinsere(reg, raiz, &inclinacao, &fim); } void inicializa(struct sbb **raiz) { *raiz = NULL; }

20 Exemplo de inserção em árvore SBB 20 Inserir a chave 5.5 na árvore a seguir

21 SBBs – análise 21 Dois tipos de altura Altura vertical h : conta o número de apontadores verticais da raiz até as folhas Altura k : o número de ponteiros atravessados (comparações realizadas) da raiz até uma folha A altura k é maior que a altura h sempre que existirem apontadores horizontais na árvore Para qualquer árvore SBB temos

22 SBBs – análise 22 Bayer (1972) mostrou que Custo para manter a propriedade SBB depende da altura da árvore O(lg(n)) Número de comparações em uma pesquisa com sucesso numa árvore SBB Melhor caso: C(n) = O(1) Pior caso: C(n) = O(lg(n)) Caso médio: C(n) = O(lg(n))

23 Exercícios 23 Desenhe a árvore SBB resultante da inserção das chaves Q U E S T A O F C I L em uma árvore vazia. Dê a lista de inserções que gera a árvore SBB abaixo:

24 Remoção 24 Para remover um nó com dois filhos, o trocamos pelo nó de maior chave à sua esquerda, ou pelo de menor chave à sua direita e removemos aquele nó Todos os nós têm dois filhos, exceto os do último nível Portanto, remoções acontecem no último nível somente É preciso manter duas condições: A altura vertical de todo nó folha é igual Não podem haver dois ponteiros sucessivos na horizontal Todos os nós têm dois filhos, exceto os do último nível

25 Remoção 25 Inicialmente, tem-se três casos principais

26 Remoção 26 Inicialmente, tem-se três casos principais Fim. Altura não mudou No interno com 1filho apenas

27 Remoção: Restaurando altura vertical e 2 filhos 27 Caso 1 e análogos Este lado perdeu 1 nível. Restaurar recursivamente Sub-árvore curta

28 Remoção: Restaurando altura vertical e 2 filhos 28 Caso 2 e análogos Dois pointeiros horizontais sucessivos Sub-árvore ganhou um nível novamente. Fim Sub-árvore curta

29 Remoção: Restaurando altura vertical e 2 filhos 29 Caso 3 e análogos Já está na horizontal Pode haver dois ponteiros horizontais sucessivos O tamanho da sub- árvore é restaurado. Fim Sub-árvore curta

30 Remoção: Restaurando altura vertical e 2 filhos 30 Caso 4 e análogos Sub-árvore curta está na horizontal Altura vertical reestabelecida. Fim

31 Retirada numa árvore SBB 31 Usaremos três procedimentos auxiliares EsqCurto: chamado quando o nó (referenciado por um apontador vertical) é retirado à esquerda e diminui a altura da árvore DirCurto: chamado quando um nó (referenciado por um apontador vertical) é retirado à direita e diminui a altura da árvore Antecessor: chamado quando um nó possui dois filhos

32 Retirada em árvore SBB – exemplos 32 Retirando 7, 5 e 9:

33 Retirada em árvore SBB – exemplos 33

34 Retirada em árvore SBB – exemplos 34

35 Retirada em árvore SBB – exemplos 35

36 Retirada em árvore SBB – exemplos 36

37 Retirada de árvore SBB – código 37 void iretira(struct registro reg, struct sbb **ptr, int *fim) { /* chegou a um nó vazio e não encontrou chave */ if (*ptr == NULL) { *fim = TRUE; return; } /* busca na sub-árvore esquerda */ if (reg.chave reg.chave) { iretira(reg, &(*ptr->esq), fim); if(!(*fim)) EsqCurto(ptr, fim); } /* busca na sub-árvore direita */ else if (reg.chave > *ptr->reg.chave) { iretira(reg, &(*ptr->dir), fim); if(!(*fim)) DirCurto(ptr, fim); } /* continua */

38 Retirada de árvore SBB – código 38 else { /* encontrou o registro */ *fim = FALSE; struct sbb *no = *ptr; if (no->dir == NULL) { /* sem filho direito */ *ptr = no->esq; free(no); if (*ptr != NULL) { *fim = TRUE; } } else if (no->esq == NULL) { /* sem filho esquerdo */ *ptr = no->dir; free(no); if (*ptr != NULL) { *fim = TRUE; } } } else { /* com dois filhos */ antecessor(ptr, &(*ptr->esq), fim); if (!(*fim)) EsqCurto(ptr, fim); }

39 Retirada de árvore SBB – código 39 void antecessor(struct sbb **q, struct sbb **ptr, int *fim) { /* busca pelo maior elemento */ if (*ptr->dir != NULL) { antecessor (q, &(*ptr->dir), fim); if (!(*fim)) { DirCurto(ptr, fim); return; } /* encontrou o maior elemento */ *q->reg = *ptr->reg; q = ptr; *ptr = *ptr->esq; free(*q); if (*ptr != NULL) *fim = TRUE;

40 Retirada de árvore SBB – código 40 void EsqCurto(struct sbb **ptr, int *fim) { if (*ptr->esqtipo == SBB_HORIZONTAL) { *ptr->esqtipo = SBB_VERTICAL; *fim = TRUE; } else if (*ptr->dirtipo == SBB_HORIZONTAL) { struct sbb *dir = *ptr->dir; *ptr->dir = dir->esq; dir->esq = *ptr; *ptr = dir; if (*ptr->esq->dir->esqtipo == SBB_HORIZONTAL) { de(&(*ptr->esq)); *ptr->esqtipo = SBB_HORIZONTAL; } else if (*ptr->esq->dir->dirtipo == SBB_HORIZONTAL) { dd(&(*ptr->esq)); *ptr->esqtipo = SBB_HORIZONTAL; } *fim = TRUE; } else { *ptr->dirtipo = SBB_HORIZONTAL; if(*ptr->dir->esqtipo == SBB_HORIZONTAL) { de(ptr); *fim = TRUE; } else if(/* checa outro lado */) {... } }}}

41 Retirada de árvore SBB – código 41 void DirCurto(struct sbb **ptr, int *fim) { if(*ptr->dirtipo == SBB_HORIZONTAL) { *ptr->dirtipo = SBB_VERTICAL; *fim = TRUE; } if (*ptr->esqtipo == SBB_HORIZONTAL) { struct sbb *esq = *ptr->esq; *ptr->esq = esq->dir; esq->dir = *ptr; *ptr = esq; if(*ptr->dir->esq->dirtipo == SBB_HORIZONTAL) { ed(&(*ptr->dir)); *ptr->dirtipo = SBB_HORIZONTAL; } else if(*ptr->dir->esq->esqtipo == SBB_HORIZONTAL) { ee(&(*ptr->dir)); *ptr->dirtipo = SBB_HORIZONTAL; } *fim = TRUE; } *ptr->esqtipo = SBB_HORIZONTAL; if(*ptr->esq->dirtipo == SBB_HORIZONTAL) { ed(ptr); *fim = TRUE; } if(*ptr->esq->esqtipo == SBB_HORIZONTAL) { ee(ptr); *fim = TRUE; } }}}


Carregar ppt "Árvores binárias de pesquisa com balanceamento Algoritmos e Estruturas de Dados II."

Apresentações semelhantes


Anúncios Google