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

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

Árvores binárias de pesquisa com balanceamento

Apresentações semelhantes


Apresentação em tema: "Árvores binárias de pesquisa com balanceamento"— 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
Pior caso para uma busca é O(n) 1 Ordem de inserção: 3 2 4 5 6

3 Árvore Binária Balanceada
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
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”
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 Á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
#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 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
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 Transformações para manter propriedadas da árvore SBB
Métodos para reorganizar casos onde aparecem dois ponteiros horizontais consecutivos Esquerda-esquerda (e direita-direita) Esquerda-direita (e direita-esquerda)

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

12 Transformações para manter propriedadas da árvore SBB - código
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 ptr esq no x x

13 Transformações para manter propriedadas da árvore SBB - código
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 ptr no dir 1 2 3 x x

14 Transformações para manter propriedadas da árvore SBB - código
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 ptr esq dir no x y x y

15 Transformações para manter propriedadas da árvore SBB - código
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; } ptr ptr dir no esq 1 2 3 x y x y

16 Inserção em árvores SBB
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 < *ptr->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
/* 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”);

18 Inserção em árvores SBB
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
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
Inserir a chave 5.5 na árvore a seguir

21 SBBs – análise 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 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 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: 4 6 2 5 8

24 Remoção 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 Inicialmente, tem-se três casos principais

26 No interno com 1filho apenas
Remoção 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
Caso 1 e análogos Sub-árvore curta Este lado perdeu 1 nível. Restaurar recursivamente

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

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

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

31 Retirada numa árvore SBB
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
Retirando 7, 5 e 9:

33 Retirada em árvore SBB – exemplos

34 Retirada em árvore SBB – exemplos

35 Retirada em árvore SBB – exemplos

36 Retirada em árvore SBB – exemplos

37 Retirada de árvore SBB – código
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 < *ptr->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); DirCurto(ptr, fim); /* continua */

38 Retirada de árvore SBB – código
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; } else { /* com dois filhos */ antecessor(ptr, &(*ptr->esq), fim); if (!(*fim)) EsqCurto(ptr, fim);

39 Retirada de árvore SBB – código
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
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
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"

Apresentações semelhantes


Anúncios Google