árvores são esquemas utilizados para representar estruturas hierárquicas, como árvores genealógicas de famílias, campeonatos de modalidades desportivas e organização de grandes empresas. as árvores podem ser utilizadas para representar decisões, definições formais de linguagem ou mesmo para representar a hierarquia entre elementos. uma árvore é uma estrutura de dados onde os dados estão dispostos de forma hierárquica (um conjunto de dados é hierarquicamente subordinado a um outro conjunto de dados). É uma estrutura de dados que organiza seus elementos de forma hierárquica, onde existe um elemento que fica no topo da árvore, chamado de raiz e existem os elementos subordinados a ele, que são chamados de nós filhos. Cada nós filho pode conter zero, um ou mais de um nós filhos. Os nós filhos que não contém outros nós filhos são chamados de nós folha. Também pode ser definido como um tipo especial de grafo. Definida usando um conjunto de nós (ou vértices) e arestas. Qualquer par de vértices está conectado a apenas uma aresta. É um grafo não direcionado, conexo e acíclico (sem ciclos). Uma árvores é composta por um conjunto de nós: Raizes: contêm zero ou mais sub-árvores, cujas raízes são ligadas diretamente à raiz inicial; Filhos: nós raízes das sub-árvores; Internos: nós com filhos; Folhas (nós externos ou terminais): não têm filhos; Direção dos ponteiros: apontam do pai para os filhos. As ligações entre os nós são os galhos ou arestas. Cada nó tem um e apenas um pai (exceto a raiz). Dado um determinado nó da árvore, cada filho seu é considerado a raiz de uma nova subárvore. O número de sub-árvores de um nó é o grau de saída daquele nó. O conjunto de zero ou mais árvores é uma floresta. Caminho na árvore é uma sequência de nós distintos, tal que existe sempre entre nós consecutivos a relação de pai e filho. Comprimento do caminho é o número de galhos entre os nós do caminho. O nível ou profundidade de um nó é o número de nós do caminho da raiz até o nó (raiz tem nível 0). A altura do nó é o número de nós no maior caminho desse nó até o seu descendente mais afastado. A altura da árvore é a altura da raiz da árvore. Árvore com apenas um nó tem altura 0 e vazia tem altura -1. Na computação, assim como na natureza, existem vários tipos diferentes de árvores. Cada uma delas foi desenvolvida pensando diferentes tipos de aplicações: árvore binária, árvores genéricas, árvore binária de busca, árvore AVL, e etc. Árvore binária é uma árvore onde o grau de cada nó é menor ou igual a dois. Há distinção entre sub-árvores da esquerda e da direita. Como a definição de árvore é recursiva, muitas operações sobre árvores binárias são definidas de forma recursiva. De maneira recursiva, podemos definir uma árvore binária como sendo: Uma árvore vazia; ou Um nó raiz tendo duas sub-árvores: a sub-árvore direita (sad) e a sub- árvore esquerda (sae). Existem três tipos de árvores binárias: Estritamente binária, Completa, e Cheia. Árvore estritamente binária cada nó possui sempre 0 (no caso de nó folha) ou 2 sub- árvores, e nenhum nó tem filho único. Na árvore binária completa a diferença de altura entre as sub-árvores de qualquer nó é no máximo 1. Se a altura da árvore é D, cada nó folha está no nível D ou D-1. Já árvore binária cheia, é uma árvore estritamente binária onde todos os nó folhas estão no mesmo nível. O percurso em árvores é o processo de visitar cada nó da árvore exatamente uma vez. Não existe uma ordem “natural” para se percorrer os nós de uma árvore. Sendo assim, são usados diferentes ordenamentos de percurso em diferentes casos. Todos os métodos são definidos recursivamente. Percorrer uma árvore binária envolve visitar a raiz e percorrer suas sub-árvores esquerda e direita. Há três maneiras recursivas de percorrer árvores binárias: pré-ordem, em-ordem e pós-ordem. No caso do percurso se realizar em pré-ordem, os nodos da árvore são visitados pela seguinte ordem: raiz, subárvore esquerda e subárvore direita. Se o percurso se realizar em em-ordem, os nodos da árvore são visitados pela seguinte ordem: subárvore esquerda, raiz e subárvore direita. Se o percurso se realizar em pós-ordem, os nodos da árvore são visitados pela seguinte ordem: subárvore esquerda, subárvore direita e raiz. Às principais operações em árvores binárias são: Inserir novo elemento: O algoritmo de inserção de um elemento numa árvore binária começa com uma pesquisa deste elemento na árvore, no sentido de procurar a posição de inserção, sendo que o nodo com o novo elemento é sempre inserido como folha da árvore. Buscar um elemento: Para procurar numa árvore binária um elemento específico deve- se examinar a raiz. Se o valor for igual à raiz, o elemento existe na árvore; caso contrário, deve-se pesquisar na subárvore da esquerda e, caso não existe nesta subárvore, deve-se então pesquisar na subárvore direita, e assim recursivamente em todos os nodos da subárvore. Mostrar todos os elementos: consiste em visitar todos os nodos desta árvore segundo determinado critério e imprimir os seus elementos. é necessário definir um método sistemático de visitar cada nodo apenas uma vez Remover um elemento: operação de remoção de um elemento duma árvore binária é mais complexo que as operações anteriores. Para se remover um elemento de uma árvore binária, deve-se considerar três casos distintos: se é uma folha, se é um nodo com um único filho ou se é um nodo com dois filhos. Uma Árvore Binária de Busca – ABB (ou de Pesquisa, search tree) é uma árvore binária cujo nó raiz contém uma chave e todas as chaves da sub-árvore esquerda são menores que a chave da raiz. Todas as chaves da sub-árvore direita são maiores que a chave raiz. As sub-árvores direita e esquerda são também Árvores Binárias de Busca. O objetivo de organizar dados em árvores binárias de pesquisa é facilitar a tarefa de procura de um determinado elemento. A partir da raiz e da chave a ser encontrada, é possível saber qual o caminho a ser percorrido até encontrar o elemento com aquela chave. Para tanto, basta verificar se a chave do elemento procurado é maior ou menor à chave do elemento na posição atual. Uma ABB é dinâmica e pode sofrer alterações (inserções e remoções de nós) após ter sido criada. As operações básicas em uma Árvore Binária de Busca são: Inserção: O primeiro elemento inserido assumirá o papel de raiz da árvore; Todo novo elemento entrará na árvore como uma folha; Se o elemento for menor ou igual à raiz será inserido no ramo da esquerda. Caso contrário, no ramo da direita (para árvores decrescentes inverte-se a a regra). Remoção: A remoção de elementos de uma ABB tem que assegurar que, após a remoção do elemento, a árvore continua a ser uma ABB. Para se remover um elemento de uma ABB, deve-se considerar três casos distintos: se é uma folha, se é um nó com um único filho ou se é um nó com dois filhos. Busca: Deve-se examinar a raiz. Se o valor for igual à raiz, o elemento existe na árvore. Se o elemento for menor do que a raiz, então deve-se buscar na subárvore da esquerda. Se o elemento for maior que a raiz, buscar na subárvore direita. Percurso: pré-ordem, em-ordem, pós-ordem. Nivel: A função para encontrar o nível de um elemento em uma ABB recebe um elemento e retorna seu nível. Árvore AVL é uma árvore binária de busca balanceada. Nessa estrutura de dados cada nó armazena uma chave e dois ponteiros, uma para a subárvore esquerda e outro para a subárvore direita. Cada nó mantém uma informação chamada fator de balanceamento (fb), que indica a diferença de altura entre as sub-árvores esquerda e direita, ou seja, fb = hD - hE. As operações de inserção e remoção mantêm o fator de balanceamento entre -1 e +1. O fb indica a situação de equilíbrio do nó: 0 está equilibrada, -1: sub-árvore esquerda tem um nível a mais que a direita. +1: sub-árvore direita tem um nível a mais que a direita. As operações realizadas na árvore AVL: Busca: A busca é a mesma utilizada em árvore binária de busca. Inserção: Para inserir um novo nó de valor K em uma árvore AVL é necessária uma busca por K nesta mesma árvore. Após a busca o local correto para a inserção do nó K será em uma subárvore vazia de uma folha da árvore. Depois de inserido o nó, a altura do nó pai e de todos os nós acima deve ser atualizada. Em seguida o algoritmo de rotação simples ou dupla deve ser acionado para o primeiro nó pai desregulado. Remoção: O primeiro passo para remover uma chave K consiste em realizar uma busca binária a partir do nó raiz. Caso a busca encerre em uma subárvore vazia, então a chave não está na árvore e a remoção não pode ser realizada. Caso encontre o elemento deve- se analisar se o elemento for uma folha da árvore, apenas exclui-lo. Se o elemento tem apenas uma subárvore, ou se o elemento tem duas subárvores. O último passo consiste em verificar a desregulagem de todos nós a partir do pai do nó excluído até o nó raiz da árvore. Aplicar rotação simples ou dupla em cada nó desregulado. Nas operações de inserção e remoção de elementos, o balanceamento da árvore resultante é ajustado através da operação de rotação. Rotação: A operação básica em uma árvore AVL geralmente envolve os mesmos algoritmos de uma árvore de busca binária desbalanceada. A rotação na árvore AVL ocorre devido ao seu desbalanceamento, uma rotação simples ocorre quando um nó está desbalanceado e seu filho estiver no mesmo sentido da inclinação, formando uma linha reta. Uma rotação-dupla ocorre quando um nó estiver desbalanceado e seu filho estiver inclinado no sentido inverso ao pai.