260 likes | 415 Views
Árvores. David Menotti Estruturas de Dados I DECOM – UFOP. Conceitos básicos. Organiza um conjunto de acordo com uma estrutura hierárquica. Contém elementos que são chamados de nós O “pai de todos” é a raiz – 1º. da hierarquia
E N D
Árvores David Menotti Estruturas de Dados I DECOM – UFOP
Conceitos básicos • Organiza um conjunto de acordo com uma estrutura hierárquica. • Contém elementos que são chamados de nós • O “pai de todos” é a raiz – 1º. da hierarquia • O contéudo de um nó pode ser de qualquer tipo que se deseje representar
Definição (Aho, Hopcroft e Ullman - 1983) • Um único nó é uma árvore. Este nó é raiz da árvore. • Suponha que n é um nó e T1, T2, ..., Tk sejam árvores com raizes n1, n2, ... , nk, respectivamente. Podemos construir uma nova árvore tornando n a raiz e T1, T2, ...., Tk sejam subárvores da raiz. Nós n1, n2, ..., nk são chamados filhos do nó n.
Caminho • Um caminho de ni a nk, onde ni é antecedente a nk,é a sequência de nós para se chegar de ni a nk. • Se ni é antecedente a nk, nk é descendente de ni • O comprimento do caminho é o número de nós do caminho – 1.
Outros conceitos • Nó que não tem antecedente: raiz; • Nós que não tem descendentes são chamados de nós folhas. (Os outros são os nós internos) • A altura de um nó na árvore é o caminho de maior comprimento que se pode fazer deste nó a uma folha. • A altura da árvore é a altura de sua raiz. • A profundidade de um nó é o comprimento da raiz até o nó (só existe um caminho)
Caminhamento • A ordem dos filhos dos nós em uma árvore pode ser ou não significativa. • Exemplos, no heap, a ordem dos filhos não tem significado • Outros casos, pode se ter um significado (como veremos em pesquisa em árvores binárias) • Considera-se que se a e b são nós irmãos, e a está à esquerda de b, então todos seus descendentes estão à esquerda de b e todos os descendentes de b.
Caminhamento • Diversas formas de percorrer ou caminhar em uma árvore listando seus nós, as principais: • Pré-ordem (Pré-fixa) • Central (Infixa) • Pós-ordem (Pós-fixa) • Para todas elas: • Se T é uma árvore nula, então a lista é nula. • Se T é uma árvore de um único nó então a lista contém apenas este nó. • O tratamento é diferenciado para os filhos • O que muda é a ordem de apresentação da raiz.
Pré-Ordem • Pré-ordem: lista o nó raiz, seguido de suas subárvores (da esquerda para a direita), cada uma em pré-ordem. Procedimento PREORDEM (n: TipoNo); Início Lista(n); Para cada filho f de n, da esquerda para direita faça PREORDEM(f); Fim
Central • Central: lista os nós da 1ª. subárvore à esquerda usando o caminhamento central, lista o nó raiz n, lista as demais subárvores (a partir da 2ª.) em caminhamento central (da esquerda para a direita) Procedimento CENTRAL (n: TipoNo); Início Se Folha(n) então /* Folha retorna se n é uma folha da árvore ou não */ Lista(n); Senão CENTRAL (FilhoMaisEsquerda(n)); Lista (n); Para cada filho f de n, exceto o mais à esquerda, da esquerda para a direita faça CENTRAL (f); Fim;
Pós-Ordem • Pós-ordem: Lista os nós das subárvores (da esquerda para a direita) cada uma em pós-ordem, lista o nó raiz. Procedimento POSORDEM Início Para cada filho f de n, da esquerda para direita faça POSORDEM(f); Lista(n); Fim;
Algoritmos e Estrutura de Dados I Exercício • Crie um TAD TNo em C cuja informação seja um inteiro e possua ponteiros para duas sub-árvores: esquerda e direita; • Escreva funções que recebam um ponteiro para a raiz da árvore e façam: • o caminhamento pré-ordem • o caminhamento pós-ordem • o caminhamento central
Algoritmos e Estrutura de Dados I TAD TNo typedef int TItem; typedef struct TNo* Apontador; typedef struct TNo { TItem Item; Apontador pEsq; Apontador pDir; } TNo;
Caminhamento: PreOrder void PreOrderRec(TNo* pRaiz) { if (pRaiz == NULL) return; printf(“%d\t”,pRaiz->Item); PreOrderRec(pRaiz->pEsq); PreOrderRec(pRaiz->pDir); }
Caminhamento: InOrder void InOrderRec(TNo* pRaiz) { if (pRaiz == NULL) return; InOrder(pRaiz->pEsq); printf(“%d\t”,pRaiz->Item); InOrder(pRaiz->pDir); }
Caminhamento: PostOrder void PostOrderRec(TNo* pRaiz) { if (pRaiz == NULL) return; PostOrder(pRaiz->pEsq); PostOrder(pRaiz->pDir); printf(“%d\t”,pRaiz->Item); }
Caminhamento: PreOrdernão recursivo void PreOrderIt(TNo* pRaiz) { TNo* pAux; TPilha P; FPVazia(&P); PEmpilha(&P,&pRaiz); while(!PEhVazia(&P)) { PDesempilha(&P,&pAux); if (pAux == NULL) continue; printf(“%d\t”,pAux->Item); PEmpilha(&P,pAux->pDir); PEmpilha(&P,pAux->pEsq); } }
Caminhamento: InOrdernão recursivo void InOrderIt(TArvoreBin* pRaiz) { TArvoreBin* pAux; TPilha P; FPVazia(&P); PEmpilha(&P,pRaiz); pAux = pRaiz->pEsq; while(!PEhVazia(&P) || pAux != NULL) { if (pAux == NULL) { PDesempilha(&P,&pAux); printf("%d\t",pAux->Item); pAux = pAux->pDir; } else { PEmpilha(&P,pAux); pAux = pAux->pEsq; } } }
Caminhamento: PostOrdernão recursivo void PostOrderIt(TArvoreBin* pRaiz) { TArvoreBin *pAux; TPilha P1,P2; FPVazia(&P1); FPVazia(&P2); PEmpilha(&P2,pRaiz); pAux = pRaiz; while(!PEhVazia(&P2) ) { PDesempilha(&P2,&pAux); PEmpilha(&P1,pAux); if (pAux->pEsq != NULL) PEmpilha(&P2,pAux->pEsq); if (pAux->pDir != NULL) PEmpilha(&P2,pAux->pDir); } while(!PEhVazia(&P1) ) { PDesempilha(&P1,&pAux); printf("%d\t",pAux->Item); } }
Exercício • Crie um TADs TNo e TArvoreBin em C que representem árvores binárias cuja informação seja um inteiro e possuam ponteiros para duas sub-árvores: esquerda e direita; • Escreva funções que recebam um ponteiro para a raiz da árvore e façam: • o caminhamento pré-ordem • o caminhamento pós-ordem • o caminhamento central
TADs TNo e TArvoreBin typedef int TItem; typedef struct TNo* Apontador; typedef struct No { TItem iItem; struct No* pEsq; /* Apontador pEsq; */ struct No* pDir; /* Apontador pDir; */ } TNo; typedef struct { TNo* pRaiz; } TArvoreBin;
Caminhamento: PreOrder void PreOrderRecX(TArvoreBin* pArv) { PreOrderRec(pArv->pRaiz); }
Caminhamento: InOrder void InOrderRecX(TArvoreBin* pArv) { InOrderRec(pArv->pRaiz); }
Caminhamento: PostOrder void PostOrderRecX(TArvoreBin* pArv) { PostOrderRec(pArv->pRaiz); }
Classificação de Árvores • Árvore Estritamente Binária • Se cada nó não-folha em uma árvore binária não tem subárvores esquerda e direita vazias
Classificação de Árvores • Árvore Binária Completa • Uma árvore binária completa de nível n é a árvore estritamente binária, onde todos os nós folhas estão no nível n.
Classificação de Árvores • Árvore Binária Quase Completa • Uma árvore binária de nível n é uma árvore binária quase completa se: • Cada nó folha na árvore esta no nível n ou no nível n-1 • Para cada nó nd na árvore com um descentente direito no nível n, todos os descendentes esquerdos de nd que são folhas estão também no nível n