Buscar

Algoritmos e Estruturas de Dados

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 48 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 48 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 48 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

PDF gerado usando o pacote de ferramentas em código aberto mwlib. Veja http://code.pediapress.com/ para mais informações.
PDF generated at: Fri, 06 Dec 2013 10:29:45 UTC
Algoritmos e Estruturas de
Dados
Conteúdo
Páginas
Objetivo 1
O que é um Algoritmo? 1
Para que servem os algoritmos? 2
Sintaxe 2
Recursividade 4
Algoritmos de Ordenação 5
Selection e Insertion 9
O que são estruturas de dados? 13
Abstração de Dados 14
Vetores e Matrizes 15
Estruturas 21
Listas 22
Pilhas 23
Filas 26
Lista encadeada 27
Tabela de Hash 29
Árvore 31
Árvores Binárias 33
Árvores AVL 35
Árvores Rubro-Negras 37
Árvores B 39
Estruturas para classes de equivalência 42
Referências
Fontes e Editores da Página 44
Fontes, Licenças e Editores da Imagem 45
Licenças das páginas
Licença 46
Objetivo 1
Objetivo
Este wikilivro tem a pretensão de tratar com aprofundamento sobre estruturas de dados e suas aplicações em
algoritmos computacionais.
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.
O que é um Algoritmo?
1.1 O que é um Algoritmo?
Algoritmo
Um algoritmo é uma sequência finita e não ambígua de instruções computáveis para solucionar um problema.
Um algoritmo consiste em uma expressão textual das etapas da resolução de algum problema, seja ele computacional
ou não. Um exemplo clássico de algoritmo não-computacional é uma receita de bolo. Outros exemplos são
instruções de montagem de um brinquedo ou equipamento, instruções para ir de um lugar a outro e receitas médicas.
Imagine a fabricação de um bolo como sendo o problema. A receita desse bolo seria o algoritmo. Os ingredientes
seriam os dados de entrada. Os recipientes utilizados para fazer o bolo são as variáveis envolvidas no processo. O
"modo de fazer" consiste na descrição dos passos a serem utilizados para obter a solução do problema.
Em computação, podemos definir um algoritmo como sendo uma forma genérica de se representar procedimentos
computacionais que, quando executados, levam à solução de uma classe de problemas de natureza semelhante.
Esta página é um esboço de informática. Ampliando-a você ajudará a melhorar o Wikilivros.
Para que servem os algoritmos? 2
Para que servem os algoritmos?
Os algoritmos são soluções para problemas computacionais, isto é, problemas que podem ser resolvidos utilizando
um ou mais computadores. Nesse sentido, as soluções de problemas computacionais são apresentadas por meio de
algoritmos, que servem para estruturar ou ordenar determinadas etapas de um processo.
Esta página é um esboço de informática. Ampliando-a você ajudará a melhorar o Wikilivros.
Sintaxe
1.3 Sintaxe
Para facilitar o entendimento dos algoritmos e, conseqüentemente, sua tradução para as diversas linguagens de
programação existentes atualmente, adotaremos uma sintaxe de descrição padrão.
Nossa sintaxe será baseada na linguagem Pascal.
• Hierarquias - As hierarquias serão denotadas pelas identações entre as linhas. Ou seja, terão a mesma ordem
hierárquica todas as instruções que estiverem a uma mesma distância da margem esquerda da tela.
• Variáveis - Não serão declaradas variáveis ou mesmo tipos de variáveis. Todas as variáveis utilizadas aparecerão
ao longo do código e serão representadas por conjuntos de letras e números.
•• ponteiros
Ponteiros receberão uma representação diferenciada, para destacá-los das variáveis comuns:
^pt - variável do tipo ponteiro (armazena um endereço de memória).
[^pt] - acesso ao conteúdo no endereço que ^pt armazena.
$var - endereço da variável var.
•• Operadores
•• atribuição
var <- 12
•• matemáticos
OPERAÇÃO OPERADOR
adição +
subtração -
multiplicação *
divisão /
módulo MOD
quociente DIV
•• lógicos
OPERAÇÃO OPERADOR
e (and) E
ou (or) OU
Sintaxe 3
não (not) ~
•• relacionais
OPERAÇÃO OPERADOR
maior >
maior ou igual >=
menor <
menor ou igual <=
igual =
diferente ~=
• Condicionais (ou blocos de seleção) - As possíveis formas de uma estrutura condicional serão:
SE (...) ENTÃO
 (...)
SENÃO SE (...) ENTÃO
 (...)
SENÃO
 (...)
SELECIONE (...) DENTRE
 [valores]:
 (...)
 SAIA
• Laços - A estrutura dos laços de repetição serão:
ENQUANTO (...) FAÇA
 (...)
PARA var <- 1,2,...,20 FAÇA
 (...)
FAÇA
 (...)
ATÉ (...)
•• Valores de retorno
Sempre que um algoritmo especificar um campo SAÍDA em sua definição (ver a seguir), em seu corpo deverá ocorrer
ao menos uma instrução RETORNA. Os algoritmos definirão os valores a serem retornados como a seguir:
RETORNE a
Estrutura dos Algoritmos
Sempre que um novo algoritmo seguir, será da seguinte forma:
ALGORITMO: NomeAlgoritmo(i, nome, ^pt)
ENTRADA: inteiro i, frase nome
[SAÍDA: quantidade de letras de nome]
[REQUISITOS: nome deve iniciar por caractere alfabético]
--------------------------------------------------------
Sintaxe 4
 (instruções)
Os campos entre colchetes são utilizados somente quando necessário.
Recursividade
Recursão é um método de programação no qual uma função pode chamar a si mesma. O termo é usado de maneira
mais geral para descrever o processo de repetição de um objeto de um jeito similar ao que já fora mostrado. Muitos
problemas em computação tem a propriedade de que cada instância sua contém uma instância menor do mesmo
problema.
A chamada à função proveniente de um meio externo a ela é denominada chamada externa e cada uma das
chamadas internas a si mesma é denominada chamada recursiva.
Um método comum de simplificação é dividir o problema em subproblemas do mesmo tipo. Como técnica de
programação, este método é conhecido como dividir e conquistar e é a chave para a construção de muitos algoritmos
importantes, bem como uma parte fundamental da programação dinâmica.
A recursão na programação é bem exemplificada quando uma função é definida em termos de si mesma. Um
exemplo da aplicação da recursão são os parsers (analisadores gramaticais) para linguagens de programação. Uma
grande vantagem da recursão é que um conjunto infinito de sentenças possíveis, designs ou outros dados podem ser
definidos, analisados ou produzidos por um programa de computador finito.
Relações de recorrência são equações que definem uma ou mais seqüências recursivamente. Alguns tipos específicos
de relações de recorrência podem ser “resolvidos” para que se obtenha uma definição não-recursiva.
Um exemplo clássico de recursão é a definição do cálculo do fatorial de um número, dada aqui no algoritmo a
seguir:
ALGORITMO: Fatorial(n) 
ENTRADA: inteiro n
SAÍDA: fatorial de n
REQUISITOS: n >= 0
SE n <= 1
 RETORNE 1
SENÃO
 RETORNE n * Fatorial(n-1)
A função chama a si mesma recursivamente em uma versão menor da entrada (n - 1) e multiplica o resultado da
chamada por n, até que alcance o caso base, de modo análogo à definição matemática de fatorial.
Como pode-se notar pela primeira condição, todo processo recursivo necessita de uma condição de parada para
evitar um loop infinito. Neste caso, quando a função fatorial atinge o valor menor ou igual a 1 ele passa a retornar o
valor de volta para a função.
No entanto, a recursão não é sempre a melhor opção. Como pode-se ver na questão acima, um laço comum resolve o
problema iterativamente. Desta forma, quando o problema é pequeno tente resolvê-lo diretamente e utilizar a
recursão apenas quando o problema for grande, consumindo tempo demais em um laço.
Recursividade 5
Resumo
• Uma recursão em computação é uma função que chama a si mesma.
• Para evitar um loop infinito é necessário estabelecer uma condição de parada.
Bibliografia
•• Recursividade na Wikipédia
• Recursão e algoritmos recursivos-Paulo Feofiloff[1]
Referências
[1] http:/ / www. ime. usp. br/ ~pf/ algoritmos/ aulas/ recu. html
Algoritmos de Ordenação
Ordenação é o ato de se colocar os elementos de uma sequência de informações, ou dados, em uma relação de
ordem predefinida. O termo técnico em inglês para ordenação é sorting, cuja tradução literal é "classificação".
Dado uma seqüencia de n dados:
O problema de ordenação é uma permutação dessa seqüencia:
tal que:
para alguma relação de ordem.
Algumas ordens são facilmente definidas. Por exemplo, a ordem numérica, ou a ordem alfabética—crescentes ou
decrescentes. Contudo, existem ordens, especialmente de dados compostos, que podem ser não triviais de se
estabelecer.
Um algoritmo que ordena uma conjunto, geralmente representada num vetor, é chamado de algoritmo de ordenação.
Algoritmo de ordenação em ciência da computação é um algoritmo que coloca os elementos de uma dada
sequência em uma certa ordem—em outras palavras, efetua sua ordenação completa ou parcial. As ordens mais
usadas são a numérica e a lexicográfica.Existem várias razões para se ordenar uma sequência. Uma delas é a
possibilidade se acessar seus dados de modo mais eficiente.
Entre os mais importantes, podemos citar bubble sort (ou ordenação por flutuação), heap sort (ou ordenação por
heap), insertion sort (ou ordenação por inserção), merge sort (ou ordenação por mistura) e o quicksort. Existem
diversos outros, que o aluno pode com dedicação pesquisar por si. Para estudo no entanto nos concentraremos nos
principais : Selection Sort, Bubble Sort e Quicksort.
Algoritmos de Ordenação 6
Natureza dos Dados
Para melhor escolha de um método de ordenação é preciso saber sobre a natureza dos dados que serão processados.
Entre elas destacam-se duas: Tempo de acesso a um elemento e a possibilidade de acesso direto a um elemento.
O tempo de acesso a um elemento é a complexidade necessária para acessar um elemento em uma estrutura;
1 Ex: Uma estante de livros com seu títulos bem visíveis.
A possibilidade de acesso direto é a capacidade ou impossibilidade de acessar um elemento diretamente na estrutura.
1 Ex: Uma pilha de livros dentro de uma caixa, onde precisamos tirar um a um para saber qual a sua
natureza.
Para classificarmos estes dois ambientes de atuação, costumamos utilizar o meio em que está armazenado os dados.
Em termos computacionais utiliza-se a designação Ordenação Interna, quando queremos ordenar informações em
memória. E Ordenação Externa, quando queremos ordenar informações em arquivo.
Selection Sort (Ordenação por Seleção)
O Selection Sort utiliza um o conceito de "selecionar o elemento mais apto". Ele seleciona o menor ou maior valor
do vetor p.ex. e passa para a primeira (ou última posição dependendo da ordem requerida), depois o segundo menor
para a segunda posição e assim sucessivamente com (n-1) elementos restantes até os dois últimos.
Teste de Mesa de Selection Sort
Vetor inicial:
4 3 1 2
Primeira passagem: Posição 0- compara 4 com 3.Como 3 é menor que 4 este é fixado como mínimo, compara 3 com
1. Como este é menor do que 3 é fixado como mínimo.Compara 1 com 2. Como continua sendo menor, é fixado. Ao
chegar ao final do vetor, como 1 é o menor elemento em comparação com o 4, eles trocam de posição.
1 3 4 2
Segunda Passagem: Posição 1- como já temos 1 como o menor elemento do vetor, passamos para a posição 1.
Comparamos 3 com 4.Como é menor, 3 continua como mínimo.Compara com 2. Como 2 é menor este é fixado
como mínimo.Ao chegar ao final do vetor, como 2 é o menor elemento em comparação com o 3, eles trocam de
posição.
1 2 4 3
Terceira Passagem: Posição 2- pegamos o elemento da posição 2 (4) e comparamos com o 3. Como 3 é o último
elemento do vetor e é menor do que 4 , trocamos as posições.Como os dois elementos são os últimos do vetor, o
Selection Sort encerra-se.
1 2 3 4
Algoritmos de Ordenação 7
Algoritmo do Selection Sort
O algoritmo normalmente é implementado por duas repetições iterando sobre a estrutura em questão. Um exemplo
de algoritmo é:
para i=0 até n-1
mínimo=i
para j=i+1 até N
se vetor[j]<vetor[mínimo]
mínimo=j
auxiliar=vetor[i]
vetor[i]=vetor[mínimo]
vetor[mínimo]=auxiliar
Bubble Sort (Ordenação Bolha)
O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais
simples. A idéia é comparar dois elementos e trocá-los de posição, até que os elementos de maior valor sejam
levados para o final do vetor. O processo continua até a ordenação total do vetor lembrando a forma como as bolhas
em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo.
A complexidade desse algoritmo é de ordem quadrática (O(n²)). Por isso, ele não é recomendado para programas que
precisem de velocidade e operem com quantidade elevada de dados. Também é necessária uma condição de parada,
geralmente uma flag ou variável que armazena se houve troca ou não na passagem. Se uma passagem chega ao seu
final sem troca a ordenação cessa.
Teste de Mesa
Vetor inicial:
4 2 5 1
Primeira Passagem: compara 4 com 2. 4 maior que 2.Mudam de posição.
2 4 5 1
Segunda Passagem: compara 4 com 5. 4 menor que 5.Permanece.
2 4 5 1
Terceira passagem: compara 5 com 1. 1 menor que 5.Mudam de posição.
2 4 1 5
Quarta passagem: compara 2 com 4. 2 menor que 4.Permanece.
2 4 1 5
Quinta passagem: compara 4 com 1. 1 menor que 4.Mudam de posição.
2 1 4 5
Sexta passagem: compara 4 com 5. 4 menor que 5.Permanece.
Algoritmos de Ordenação 8
2 1 4 5
Sétima passagem: compara 2 com 1. 1 menor que 2.Trocam de posição.
1 2 4 5
Oitava passagem: compara 2 com 4. 2 menor do que 4.Permanece.
1 2 4 5
Nona passagem: compara 4 com 5. 4 menor do que 5. Permanece.
1 2 4 5
Décima passagem: não há mudanças. Sai do laço.
1 2 4 5
Algoritmo Bubble Sort
O algoritmo pode ser descrito em pseudo-código como segue abaixo. V é um VETOR de elementos que podem ser
comparados e n é o tamanho desse vetor.
BUBBLESORT (V[], n) 1 houveTroca <- verdade # uma variável de controle
2 enquanto houveTroca for verdade faça
3 houveTroca <- falso
4 para i de 1 até n-1 faça
5 se V[i] vem depois de V[i + 1]
6 então troque V[i] e V[i + 1] de lugar e
7 houveTroca <- verdade
Quicksort (Ordenação Rápida)
O quicksort (Ordenação Rápida) é um método de ordenação baseado no conceito de dividir-e-conquistar.
Inicialmente ele seleciona um elemento o qual é chamado de pivô, depois remove este pivô e particiona os elementos
restantes em duas sequências, uma com os valores menores do que o pivô e outras com valores maiores.
Resumo
• Algoritmo de ordenação é uma implementação em uma linguagem de programação para ordenar um conjunto de
dados.
•• Existem diversos tipos de algoritmos de ordenação. Os principais são Selection Sort, Bubble Sort e Quicksort.
Algoritmos de Ordenação 9
Ligações externas
• Sorting Algorithm na Wikipédia em inglês [1]
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.
Referências
[1] http:/ / en. wikipedia. org/ wiki/ Sorting_algorithm
Selection e Insertion
Insertion
Implementações
Pseudocódigo
Segue uma versão simples do pseudocódigo do algoritmo, com vetores começando em zero:
 INSERTION_SORT(A, size) 
 for j ←2 to size do 
 key ← A[ j] 
 i ← j –1 
 while i > 0 and A[i] > key do 
 A[i+1] ← A[i] 
 i ← i –1 
 A[i+1] ← key 
xHarbour
Function SortInsertion( aList )
 Local nLoop1 := 0
 Local nLoop2 := 0
 Local nIndex := 0
 For nLoop1 := 1 To Len( aList )
 nLoop2 := nLoop1
 nIndex := aList[ nLoop1 ]
 While nLoop2 > 1 .And. aList[ nLoop2 - 1 ] > nIndex
 aList[ nLoop2 ] := aList[ nLoop2 - 1 ]
 nLoop2 --
 EndDo
 aList[nLoop2 ] := nIndex
 Next
Return NIL
Selection e Insertion 10
Java
 public static Integer[] insertionSort(Integer[] array) {
 for (int i = 1; i < array.length; i++) {
 int a = array[i];
 int j;
 for (j = i - 1; j >= 0 && array[j] > a; j--)
 array[j + 1] = array[j];
 array[j] = a;
 }
 return array;
 }
Visual Basic
 Private Sub Ordenacao(Numeros() As Integer)
 Dim i As Long
 Dim j As Long
 Dim iMin As Long
 Dim iMax As Long
 Dim varSwap As Variant
 iMin = LBound(Numeros) + 1
 iMax = UBound(Numeros)
 For i = iMin To iMax
 varSwap = Numeros(i)
 For j = i To iMin Step -1
 If varSwap < Numeros(j - 1) Then Numeros(j) = Numeros(j - 1) Else Exit For
 Next j
 Numeros(j) = varSwap
 Next i
End Sub
'Code By Kalandar
C
void insertionSort(int *primeiro, int *ultimo)
{
 int aInserir, *posAIncio + 1, *posAtual;
 for (; posAInsir <= ulmo; ++posAInserir)
 {
 aInserir = *posAInserir;
 posAtual = posArir - 1;
 while (Atual >= priro && *posAtual > aerir )
 {
 *(posAtu+1) = *posAtual;
 --posal;
 }
 *(posl+1) = aInserir;
 }
}
Selection e Insertion 11
Outra versão em C:
void insertionSort(int v[], int n)
{
 int i, j, chave;
 
 for(j=1; j<n; j++) 
 {
 chave = v[j];
 i = j-1;
 while(i >= 0 && v[i] > chave)
 {
 v[i+1] = v[i];
 i--;
 } 
 v[i+1] = chave;
 }
}
Pascal
procedure InsertionSort(var a:vetor; n:integer; var NC, NT: integer);
var j,o:integer; {variaveis auxiliares}
begin
for j:=2 to n do
 begin
o:=j-1;
 while (a[j]<a[o]) and (i>1) do
 begin
 inc(NT);
 troca(a[j],a[o]);
 j:=i-1;
 o:=o-1;
 inc(NC);
 end;
 end;
end;
Python
def inssort(v):
 for j in range(1, len(v)):
 key = v[j]
 i = j - 1
 while a[i] > key and i >= 0:
 a[i+1] = a[i]
 i -= 1
 v[i+1] = key
Selection e Insertion 12
Haskell
import Data.List (insert)
insertsort :: Ord a => [a] -> [a]
insertsort = foldr insert []
C#
 static int[] ordernar(int[] A)
 { 
 int i, j, index;
 for (i = 1; i < A.Length; i++)
 {
 index = A[i];
 j = i;
 while ((j > 0) && (A[j - 1] > index))
 {
 A[j] = A[j - 1];
 j = j - 1;
 }
 A[j] = index;
 }
 return A;
 }
PHP
/**
 * @author Nissius Guilet Ribas
 * @copyright 2009
 *
 * Correção, no while, não é j>=0 e sim j>0;
 */
ini_set('max_execution_time','600');
function microtime_float()
{
 list($usec, $sec) = explode(" ", microtime());
 return ((float)$usec + (float)$sec);
}
for ($gera = 0; $gera <=20000; $gera++){
 $array[$gera] = rand(0, 10000);
}
$time_start = microtime_float();
for($i = 1; $i < count($array); $i++){
 $copiado = $array[$i];
Selection e Insertion 13
 $j = $i;
 while (($j > 0 ) && ($copiado < $array[$j-1])){
 $array[$j] = $array[$j-1];
 $j--;
 }
 $array[$j] = $copiado; 
}
$time_end = microtime_float();
//Mostra o tempo que levou para ordenar
echo $time = $time_end - $time_start;
//Exibe a ordenação
print_r ($array);
O que são estruturas de dados?
Estruturas de dados (Data Structures) é o nome dado a organização de dados e algoritmos de forma coerente e
racional de modo a otimizar o seu uso. De acordo com o modo como um conjunto de dados são organizados e como
as operações que são efetuadas sobre estes dados pode-se solucionar de forma simples problemas extremamente
complexos.
Existem diversos modelos de estruturas de dados, e novos modelos são criados constantemente pois acompanham
também a evolução dos algoritmos e das linguagens de programação. Neste livro iremos abordar as estruturas
clássicas, as quais podem ser utilizadas com sucesso na maioria dos casos.
É um dos temas fundamentais da ciência da computação, utilizado nas mais variadas áreas e para as mais variadas
finalidades. No entanto para começarmos a entender o conceito devemos, antes entender o conceito de algoritmos,
pois algoritmos manipulam dados.
Dados quando estão organizados de uma forma coerente representam uma estrutura de dados. Escolher uma estrutura
de dados ideal pode tornar-se um problema difícil para uma determinada solução. As pesquisas e estudos das
estruturas de dados estão em constante desenvolvimento, apesar disso, existem estruturas que têm se mostrado
padrão, ou seja, são clássicas.
Estruturas de dados possuem características básica, no entanto finalidades bastante diversas. Podem ser
implementadas usando vetores (estático) ou ponteiro (dinâmico).
Abstração de Dados 14
Abstração de Dados
Processos
Um processo é uma sequência ordenada de procedimentos (ou operações) realizadas sobre dados imputados na
máquina computacional de modo a gerar uma solução desejada.
Abstração de Dados
Abstração de dados lida com a representação conceitual dos dados de modo a se implementar algoritmos que
possibilitem a solução mais prática dos problemas apresentados.
Tipos de Dados
A unidade de informação mais básica de uma máquina computacional elétrica é o bit, representado simbolicamente
pelo estado um e zero (estados ligado e desligado). Os bits são agrupados e combinados de forma a representar uma
grande variedade de informação. Devido as dificuldades de se operar e manipular dados a nível de bit (linguagem de
máquina) foram desenvolvidas as linguagens de programação através do qual podemos operar e representar uma
grande quantidade de dados de uma forma mais prática. Estes dados são agrupados em tipos sobre as quais
realizamos uma série de funções de acordo com modelos matemáticos para atingir uma solução.
No entanto em toda e qualquer implementação devemos :
•• Reconhecer as limitações da implementação;
•• Analisar as diversas implementações que podem ser realizadas com os mesmos tipos de dados;
•• Dentre estas escolher a mais adequada para resolver um problema específico;
•• Entender o espaço de armazenamento utilizado e o tempo de execução.
Vetores e Matrizes 15
Vetores e Matrizes
Vetor (Array)
Em computação um Vetor (Array) ou Arranjo é o nome de uma matriz unidimensional considerada a mais simples
das estruturas de dados. Geralmente é constituída por dados do mesmo tipo (homogêneos)e tamanho que são
agrupados continuamente na memória e acessados por sua posição (indíce - geralmente um número inteiro) dentro
do vetor. Na sua inicialização determina-se o seu tamanho que geralmente não se modifica mesmo que utilizemos
menos elementos.
Abaixo temos o exemplo de um vetor. Os valores internos seriam os dados alocados no vetor, enquanto seu tamanho
é dado pelo número de casas disponíveis (no caso 8) e o índice representa a posição do dado no vetor ( por exemplo
podemos definir que 0 tem o índice 1, 2 tem índice 2, 8 tem índice 3 e assim sucessivamente).
0 2 8 9 10 11 15 18
•• Declaração e inicialização de um vetor
A declaração de um vetor em português estruturado pode ser da seguinte forma:
 Nome_Vetor:vetor[tamanho]tipo
Assim temos como exemplo de declarações:
 VECTOR:vetor [10] numérico
 MEDIA: vetor [3] numérico
Tomemos o primeiro exemplo (inteirovector [10]) onde declaramos que estamos criando um vetor para números
chamado de VECTOR com dez posições. Desta forma o computador entende que deve alocar 10 espaços para 10
números inteiros no computador que serão inseridos conforme especificado pelo programa . Por exemplo, vamos
construir dois laços de repetição:
 VECTOR:vetor [10] numérico
 INDICE:numérico
 INDICE<-0
 para INDICE de 0 até VECTOR<9 passo 1 faça
 exibe Escreva um número 
 recebe VECTOR [INDICE]
 fecha_para
 para INDICE de 0 até VECTOR<9 passo 1 faça
 exibeVECTOR [INDICE]
 recebe VECTOR [INDICE]
 fecha_para
Conforme vimos, o primeiro laço para vai entender que ao entrar índice<-0 , quando o usuário digitar o primeiro
valor será alocado este valor em vector[índice].Quando chegar ao final do para ele fará o teste. Se o índice continuar
menor do que 10 ele entra no laço e recebe o segundo valor, chegando ao final do laço e fazendo novamente o
processo até obter os dez valores quando sai do laço.
No segundo laço acessamos estes dados e exibimos na tela aplicando o mesmo príncipio do primeiro laço.
Vetores e Matrizes 16
Operações com Vetores
Podemos trabalhar com vetores numéricos, executando operações sobre eles da mesma forma como executaríamos
com variáveis numéricas comuns. Devemos assumir que ao declararmos um determinado vetor[índice], com um
índice específico, estamos fazendo referência a um número.
Matrizes
Matrizes são arranjos ordenados que ao contrário dos vetores podem ter n dimensões, sendo que estas dimensões
lhes dão o nome n-dimensional . Uma matriz de duas dimensões será chamada bi-dimensional, uma de três
dimensões tri-dimensional e assim consecutivamente. Funciona praticamente da mesma forma que um vetor exceto
que utilizaremos o número n de índices para acessar um dado que queremos. Para efeitos de estudo por enquanto nos
limitaremos somente às matrizes bidimensionais (duas dimensões linha X colunas). Assim se possuimos uma matriz
bidimensional de duas linhas e duas colunas:
3 4
5 6
Consideramos que para acessarmos o valor 3, localizamos o índice por sua linha (1) e coluna (1) , deste modo seu
índice é (1,1). O valor quatro por exemplo será (1, 2).
•• Declaração e inicialização de um matriz
A declaração de uma matriz em português estruturado pode ser da seguinte forma:
tipo Nome_Matriz
[tamanho_linha][tamanho_coluna]
Assim temos como exemplo de declarações:
 inteiro matriz [10][10] 
 real media [3][3]
Em uma matriz como o inteiro matriz que criamos acima é criado espaço para 100 elementos (10x10).Criaremos
abaixo um algoritmo em que o usuário digita 100 elementos e estes aparecem na tela.
inteiro matriz [10][10]
inteiro i , j (i será o índice linha e j o índice
coluna)
para (início: i=0 fim i<10
alteraçãoi+1 )
para
(início:
j=0 fim
j<10
alteraçãoj+1
)
exibe
Escreva
um
número
Vetores e Matrizes 17
recebe
matriz
[i][j]
fecha_para
fecha_para
para (início: i=0 fim i<10
alteraçãoi+1 )
para
(início:
j=0 fim
j<10
alteraçãoj+1
)
exibe Estes são os números
digitados:
exibe matriz [i][j]
fecha_para
fecha_para
Operações com matrizes
Soma e subtração entre matrizes
inteiro matriz_A [2][2]
inteiro matriz_B [2][2]
inteiro matriz_soma [2][2]
para (início: i=0 fim i<2
alteraçãoi+1 )
para
(início:
j=0 fim
j<10
alteraçãoj+1
)
matriz_soma[i][j]=
matriz_A
[i][j]+
matriz_B
[i][j]
fim_para
fim_para
Vetores e Matrizes 18
Multiplicação por um escalar
inteiro escalar
inteiro matriz_A [2][2]
inteiro matriz_multiplicação [2][2]
para (início: i=0 fim i<2
alteraçãoi+1 )
para
(início:
j=0 fim
j<2
alteraçãoj+1
)
matriz_multiplicação[i][j]=
escalar *
matriz_A
[i][j]
fim_para
fim_para
Multiplicação entre matrizes
inteiro matriz_A [2][2]
inteiro matriz_B [2][2]
inteiro matriz_multiplicacao [2][2]
para (início: i=0 fim i<2
alteraçãoi+1 )
para
(início:
j=0 fim
j<2
alteraçãoj+1
)
para
(início:
k=0
fim
k<2
alteraçãok+1
)
matriz_multiplicacao[i][j]=
matriz_multiplicacao
[i][j]+
matriz_A
[i][k]*matriz_B[k][j]
fim_para
Vetores e Matrizes 19
fim_para
Calcular a diagonal e a transposta
inteiro matriz_A [2][2]
inteiro diagonal=0
para (início: i=0 fim i<2
alteraçãoi+1 )
para
(início:
j=0 fim
j<10
alteraçãoj+1
)
se
(i=j)
diagonal=
diagonal+
matriz_A
[i][j]
fim_se
fim_para
fim_para
inteiro matriz_A [2][2]
inteiro inversa=0
inteiro maximo=2
para (início: i=0 fim i<2
alteraçãoi+1 )
para
(início:
j=0 fim
j<2
alteraçãoj+1
)
se
(i+j=(maximo*2)-1)
inversa=
inversa
+
matriz_A
[i][j]
fim_se
fim_para
fim_para
Vetores e Matrizes 20
Resumo
1. include<stdio.h>
2. include<stdlib.h>
1.1. define t 3
int main(){
 int mat[t][t], i, j;
 for(i = 0; i<t; i++){
 for(j = 0; j<t; j++){
 printf("Digite o elemento mat[%d][%d]", i, j);
 scanf("%d", &mat[i][j]);
 }
 }
 for(i = 0; i<t; i++){
 for(j=0; j<t; j++){
 printf("mat[%d][%d] = %d, ", i, j, mat[i][j]);
 }
 printf("\n");
 }
system("pause");
 return 0;
}
Bibliografia
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.
Estruturas 21
Estruturas
Uma estrutura ou registro é o nome dado a alocação de uma ou mais váriaveis de tipos diferentes agrupadas sob
um único nome. Estruturas constituem um importante recurso para organizar os dados de um programa já que trata
um grupo de valores como uma única variável.
Sua sintaxe básica é:
 Nome da estrutura: estrutura 
 {declaração das variáveis}
 fim_estrutura
Ao criarmos um registro, criamos um tipo especial de dado que armazena dentro de si todas as variáveis declaradas
pelo programador. Ao ser chamado pelo usuário, o registro aloca na memória o espaço necessário para aceitação de
todas estas variáveis.
Para escrever ou ler as variáveis armazenadas em uma estrutura, basta apenas especificarmos o nome da estrutura,
seguido de ponto e a variável interna que desejamos acessar.
 Nome da estrutura.nome da variável interna
Exemplo de uso de estrutura
 início
 FUNCIONARIO: estrutura
 CÓDIGO: numérico
 NOME: literal
 SALARIO: numérico
 fim_estrutura
 FUNCIONARIO.SALARIO<-0.00
 escreva "Digite a matrícula do funcionário : "
 leia FUNCIONARIO.MATRICULA
 escreva "Digite o nome do funcionário : "
 leia FUNCIONARIO.NOME
 escreva "Digite o salário do funcionário : "
 leia FUNCIONARIO.SALARIO
 escreva "O funcionário", FUNCIONARIO.MATRICULA "chamado",FUNCIONARIO.NOME "recebe",
 FUNCIONARIO.SALARIO 
 fim
Estruturas 22
Classes como estruturas
As linguagens com orientação a objetos possuem recursos para criar classes, e elas podem funcionar como estruturas
contendo variáveis não-estáticas.
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.
Listas
Um exemplo de uma lista- uma simples lista
ligada com três valores inteiros
Lista é definido como uma implementação de um tipo de dado abstrato
(ADT), formalizando o conceito de uma coleção ordenada de
entidades.Uma lista trata-se de uma série finita de dados, cuja principal
propriedade baseia-se na posição relativa dos elementos dispostos
linearmente. Uma lista tem as seguintes propriedades:
•• se a lista é vazia ; n=0 senão:
•• a1 é o primeiro elemento da lista (cabeça);
•• an é o último elementoda lista;
• ak é um elemento entre a1 e an (1<k<n).
Diversas operações podem ser realizadas sobre uma lista como :
•• Acessar um elemento qualquer da lista;
•• Inserir um elemento em uma posição especificada da lista;
•• Excluir um elemento em uma posição especificada da lista;
•• Combinar duas listas em uma;
•• Particionar uma lista em duas;
•• Ordenar elementos de uma lista;
•• e outras.
Casos especiais de listas
Conforme o modo como uma lista é estruturada, e como esta é manipulada, podemos nos referir a ela de forma mais
específica.
Pilha
Pilha é um modelo de lista onde as operações de inserção, remoção e acesso aos dados são feitos em um único
extremo. Por isto este modelo é também chamado de LIFO (Last In - First Out).
Filas
Fila é um modelo de lista onde a operação de inserção é efetuada por um extremo e a remoção pelo outro extremo.
Por isto este modelo é também chamado de FIFO (First In - First Out).
Pilhas 23
Pilhas
Uma representação simplificada de uma Pilha
Pilha ou stack é um tipo especial de lista linear em que todas as
operações de inserção e remoção são realizadas pela mesma
extremidade chamada topo.
Os elementos são removidos na ordem do programa inversa
daquela em que foram inseridos de modo que o último elemento
que entra é sempre o primeiro ser executado , por isto este tipo de
estrutura é chamada LIFO (Last In - First Out).
O exemplo mais prático que costuma utilizar-se para entender o
processo de pilha é como uma pilha de livros ou pilha de pratos,
no qual ao se colocar diversos elementos uns sobre os outros, se
quisermos pegar o livro mais abaixo deveremos tirar todos os
livros que estiverem sobre ele."
Operações sobre pilhas
Uma pilha geralmente suporta 4 operações básicas:
• TOP: acessa-se o elemento posicionado no topo da pilha;
• PUSH: insere um novo elemento no topo da lista;
• POP: remove o elemento do topo da lista.
• PULL:altera o elememto posicionado no topo da pilha;
As pilhas são úteis quando queremos armazenar temporariamente uma informação que vamos usar logo depois. Se
tivermos uma pilha p e um elemento x qualquer, a operação PUSH (p,x) acrescenta o elemento x no topo da pilha e
aumenta-lhe o tamanho. Já a operação POP(P) remove o elemento que está no topo da pilha fazendo com que esta
diminua. Já a operação TOP não altera o tamanho da estrutura , pois simplesmente visita o topo da pilha retornado
uma cópia do elemento que encontra-se no seu topo.
Visualização do comportamento de uma pilha
Na tabela abaixo é descrito o comportamento de uma pilha. A primeira coluna descreve qual operação é efetuada
sobre uma pilha que inicia vazia, a segunda coluna descreve os elementos da pilha e como estão organizados
(estando o "topo" à direita), visualização descreve o elemento visitado quando utilizado o TOP e a quarta coluna
mostra a quantidade de elementos na pilha.
Operação Pilha Visualização Tamanho da Pilha
PUSH (P,1) 1 1
PUSH (P,2) 1,2 2
TOP 1,2 2 2
PUSH (P,3) 1,2,3 3
POP (P) 1,2 2
POP (P) 1 1
POP (P) 0
Pilhas 24
Operações auxiliares
Ao implementar uma pilha dentro do computador a quantidade de memória alocada funciona como um dos fatores
limitantes da pilha. Assim são necessárias mais três operações para manipular corretamente a estrutura.
• INIT: inicia a pilha como "Vazia"
• IS_EMPTY: verifica se a pilha está "Vazia"
• IS_FULL: verifica se a pilha está "cheia"
Toda vez que criamos uma estrutura de pilha, esta deve ser inicializada para garantir que não haja nenhuma "sujeira"
no local onde esteja montada. Para verificar se uma pilha P está vazia, devemos usar uma função Is_Empty(P) que
retorna verdadeiro se uma pilha estiver vazia. A função Is_Full (P) é utilizada para verificar se a pilha está cheia,
retornando verdadeiro caso não haja espaço para armazenar mais elementos.
Is_Full não é o contrário de Is_Empty. Quando Is_Empty retorna falso, não siginifica no entanto que ela esteja cheia.
Do mesmo modo se uma função Is_Full retorna falso não significa que a pilha esteja vazia.
Pseudo-código de uma pilha
 record Nodo {
 data //informação a ser armazenada no nodo
 próximo // referência ao próximo nodo; null para o último nodo
 }
 record Stack {
 Node stackPointer // ponteiro para o nodo do topo; valor null para uma pilha vazia
 }
 function push(Stack stack, Element element) { // insere elemento em uma pilha
 new(newNode) // Allocate memory to hold new node
 newNode.data := element
 newNode.next := stack.stackPointer
 stack.stackPointer := newNode
 }
 function pop(Stack stack) { // retira o elemento do topo e retorna o nodo do topo agora
 node := stack.stackPointer
 stack.stackPointer := node.next
 element := node.data 
 return element
 }
 function top(Stack stack) { // retorna o nodo no topo
 return stack.stackPointer.data
 }
 function length(Stack stack) { // retorna a quantidade de nodos na pilha
 length := 0
 node := stack.stackPointer
 while node not null {
 length := length + 1
 node := node.next
 }
Pilhas 25
 return length
 }
Aplicações de Pilhas
Pilhas são utilizados em diversas aplicações em Ciência da Computação. Um dos mais salientes casos é a análise de
expressões e sintaxe. Calculadores que utilizam a Notação Polonesa Reversa utilizam pilha para expressar seus
valores, podendo ser representadas de forma prefixa, posfixa ou infixa. Conversões de uma forma de expressão para
outras também necessitam de pilhas. Muitos compiladores utilizam pilhas para análise sintática de expressões,
blocos de programas e afins.
Exemplo de uso de pilha em Notação Polonesa Reversa
Por exemplo: ((1 + 2) * 4) + 3 em notação pós-fixa
1 2 + 4 * 3 +
Utilizando uma pilha consideramos:
•• empilhar quando encontrar um operando;
•• sacar dois operandos e achar o valor quando encontrar uma operação.
•• empilhar o resultado.
Entrada Operação Pilha
1 push operando 1
2 push operando 1, 2
+ adicionar 3
4 Push operando 3, 4
* multiplicar 12
3 push operando 12, 3
+ adicionar 15
O resultado final 15 estará no topo da pilha no fim do cálculo.
Bibliografia
• Stack program in c++ [1]
• Stack Machines - the new wave [2]
• Bounding stack depth [3]
• Libsafe - Protecting Critical Elements of Stacks [4]
• Stack Size Analysis for Interrupt-driven Programs [5] (322 KB)
• Stack Implementation ( Graphical & Text Mode) [6] C Language implementation of Stack
• Pointers to stack visualizations [7]
Pilhas 26
Referências
[1] http:/ / 24bytes. com/ stack. html
[2] http:/ / www. ece. cmu. edu/ ~koopman/ stack_computers/ index. html
[3] http:/ / www. cs. utah. edu/ ~regehr/ stacktool
[4] http:/ / research. avayalabs. com/ project/ libsafe/
[5] http:/ / www. cs. ucla. edu/ ~palsberg/ paper/ sas03. pdf
[6] http:/ / www. mycplus. com/ utilitiesdetail. asp?iPro=1
[7] http:/ / web-cat. cs. vt. edu/ AlgovizWiki/ Stacks
Filas
Fila, também chamado de FIFO (acrônimo do inglês First In, First Out , primeiro a entrar, primeiro a sair) é o nome
dado a estrutura de dados em que ocorrem inserção de dados em um extremo e sua saída por outro, obedecendo
assim "a ordem de chegada" como se fosse uma fila comum de pessoas. A implementação pode realizar-se com
ajuda de vetores, assim como através do uso de ponteiros. Se a fila é implementada com o uso de vetores, o número
máximo de elementos armazenados deve ser estabelecido no código do programa antes da compilação (fila estática)
ou durante sua execução (fila pseudo-estática).
Operações básicas
As filas tem duas operações básicas:
• Enqueue: inserir um elemento no final da fila.
• Dequeue: remover um elemento do começo da fila.
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.Lista encadeada 27
Lista encadeada
Diagrama conceitual de uma lista ligada.
Lista ligada ou Lista encadeada é uma estrutura de
dados linear e dinâmica. Ela é composta por uma
sequência de nodos ou células que contém seus dados e
também uma ou duas referências ("links") que apontam
para o nodo anterior ou posterior. Há diversos modelos
de lista ligadas como lista-encadeada simples, listas
duplamente ligadas e listas encadeadas circulares.
Para se "ter" uma lista ligada, basta guardar seu primeiro elemento, e seu último elemento aponta para uma célula
nula. O esquema a seguir representa uma lista ligada com 5 elementos:
Célula 1 ---> Célula 2 ---> Célula 3 ---> Célula 4 ---> Célula 5 ---> (Nulo)
Para manipularmos estas listas nomeadamente: inserir dados ou remover dados temos que ter sempre em atenção em
ter um ponteiro que aponte para o 1º elemento e outro que aponte para o fim, isto porque se queremos inserir ou
apagar dados que estão no inicio ou no fim da lista então a operação é rápidamente executada caso seja um nó que
esteja no meio da lista pois terá que haver uma procura até encontrar a posição desejada.
Tipos de listas encadeadas
Lista encadeada simples
Uma lista encadeada simples é aquela que contém apenas um link por nodo. Este link aponta para o próximo nodo da
lista, ou para um valor nulo (vazio) quando se trata do nodo final.
Lista encadeada simples com três valores inteiros.
Lista duplamente encadeadas
Listas duplamente encadeadas ou lista de duas vias, são um modelo mais sofisticado das listas simples: cada nodo
possui dois ponteiros - um que aponta para o nodo anterior (ou null se é o primeiro valor ou a lista está vazia) e outro
que aponta para o próximo nodo (ou null se é o último nodo ou a lista está vazia).
Um exemplo de uma lista duplamente encadeada
Lista encadeada 28
Listas encadeadas circulares
Na lista encadeada circular, o primeiro e o último nodo são ligados entre si. Nas listas circulares simples, há apenas
um link que aponta para o próximo nodo; enquanto nas listas circulares duplas há dois links em cada nodo que
apontam para o elemento anterior e para o posterior.
Um exemplo de uma lista circular simples
Pseudo-código de listas encadeadas
Lista encadeada simples
 record Node {
 data // O dado a ser armazenado no nodo
 next // Referência ao próximo nodo; null se for o último nodo
 }
 record List {
 Node firstNode // ponteiro para o primeiro nodo da lista; null para uma lista 
 vazia
 }
Atravessar uma lista simples é fácil iniciando pelo primeiro nodo e seguindo cada next até o fim.
 node := list.firstNode
 while node not null {
 node := node.next
 }
Tabela de Hash 29
Tabela de Hash
Em ciência da computação a tabela hash (de hashing, no inglês), também conhecida por tabela de espalhamento, é
uma estrutura de dados especial, que associa chaves de pesquisa (hash) a valores. Seu objetivo é, a partir de uma
chave simples, fazer uma busca rápida e obter o valor desejado. É algumas vezes traduzida como tabela de
escrutínio.
Complexidade e usos comuns
Tabelas hash são tipicamente utilizadas para implementar vetores associativos, sets e cache|caches. São tipicamente
usadas para indexação de grandes volumes de informação (como bases de dados). A implementação típica busca
uma função hash que seja de complexidade O(1), não importando o número de registros na tabela (desconsiderando
colisões). O ganho com relação a outras estruturas associativas (como um vetor simples) passa a ser maior conforme
a quantidade de dados aumenta. Outros exemplos de uso das tabelas hash são as tabelas de transposição em jogos de
xadrez para computador até mesmo em serviços de DHCP.
A função de espalhamento
A função de espalhamento ou função hash é a responsável por gerar um índice a partir de determinada chave. Caso a
função seja mal escolhida, toda a tabela terá um mau desempenho.
O ideal para a função de espalhamento é que sejam sempre fornecidos índices únicos para as chaves de entrada. A
função perfeita seria a que, para quaisquer entradas A e B, sendo A diferente de B, fornecesse saídas diferentes.
Quando as entradas A e B são diferentes e, passando pela função de espalhamento, geram a mesma saída, acontece o
que chamamos de colisão.
Na prática, funções de espalhamento perfeitas ou quase perfeitas são encontradas apenas onde a colisão é intolerável
(por exemplo, nas funções hash da criptografia), ou quando conhecemos previamente o conteúdo da tabela
armazenada). Nas tabelas hash comuns a colisão é apenas indesejável, diminuindo o desempenho do sistema. Muitos
programas funcionam sem que seu responsável suspeite que a função de espalhamento seja ruim e esteja
atrapalhando o desempenho.
Por causa das colisões, muitas tabelas hash são aliadas com alguma outra estrutura de dados, tal como uma lista
encadeada ou até mesmo com árvore AVL|árvores balanceadas. Em outras oportunidades a colisão é solucionada
dentro da própria tabela.
Exemplo de função de espalhamento e colisão
Imagine que seja necessário utilizar uma tabela hash para otimizarmos uma busca de nomes de uma lista telefônica
(dado o nome, temos que obter o endereço e o telefone). Nesse caso, poderíamos armazenar toda a lista telefônica em
um vetor e criar uma função de espalhamento que funcionasse de acordo com o seguinte critério:
 Para cada nome começado com a letra A, retornar 0
 Para cada nome começado com a letra B, retornar 1
 ...
 Para cada nome começado com a letra Z, retornar 25
O exemplo anterior poderia ser implementado, em Linguagem de programação C|C, da seguinte forma:
 int hashExemplo(char * chave)
 {
 return (chave[0]-65);
Tabela de Hash 30
 }
Agora inserimos alguns nomes em nossa lista telefônica:
José da Silva; Rua das Almas, 35; Telefone (11) 888-9999
Ricardo Souza; Rua dos Coqueiros, 54; Telefone (11) 222-4444
Orlando Nogueira; Rua das Oliveiras, 125; Telefone (11) 444-5555
Agora inserimos mais um nome:
Renato Porto; Rua dos Elefantes, 687; Telefone (11) 333-5555
Como se pode notar, a função de exemplo causaria muitas colisões. Se inserirmos um outro nome começado com a
letra R, teremos uma outra colisão na letra R. Se inserirmos "João Siqueira", a entrada estaria em conflito com o
"José da Silva".
Resolvendo colisões
Um bom método de resolução de colisões é essencial, não importando a qualidade da função de espalhamento.
Considere um exemplo derivado do paradoxo|paradoxo do aniversário: mesmo que considerarmos que a função irá
selecionar índices aleatórios uniformemente em um vetor de um milhão de posições, há uma chance de 95% de haver
uma colisão antes de inserirmos 2500 registros.
Há diversos algoritmos de resolução de colisão, mas os mais conhecidos são Encadeamento Separado e
Endereçamento Aberto.
Encadeamento Separado
É a solução mais simples, em que normalmente um registro aponta para uma lista encadeada em que são
armazenados os registros em conflito. A inserção na tabela requer uma busca e inserção dentro da lista encadeada;
uma remoção requer atualizar os índices dentro da lista, como se faria normalmente.
Estruturas de dados alternativas podem ser utilizadas no lugar das listas encadeadas. Por exemplo, se utilizarmos
uma Árvore AVL|árvore balanceada, podemos melhorar o tempo médio de acesso da tabela hash para O(log n) ao
invés de O(n). Mas como as listas de colisão são projetadas para serem curtas, o overhead causado pela manutenção
das árvores pode fazer o desempenho cair.
Apesar disso, as árvores podem ser utilizadas como proteção contra ataques que buscam criar overhead
propositalmente - descobrindo uma forma da função gerar repetidamente o mesmo índice - e derrubar o sistema
(ataques DOS). Nesse caso, uma árvore balanceada ajudaria o sistema a se manter estável, por ser uma estrutura com
grande capacidadede crescimento.
Endereçamento Aberto
No método de Endereçamento Aberto os registros em conflito são armazenados dentro da própria tabela. A resolução
das colisões é realizadas através de buscas padronizadas dentro da própria tabela.
A forma mais simples de fazer a busca é procurar linearmente na tabela até encontrar um registro vazio ou o registro
buscado. Outras formas utilizadas incrementam o índice exponencialmente: caso o registro não seja encontrado na
posição 10, será buscado na posição 100, depois na posição 1000. A inserção tem que seguir o mesmo critério da
busca.
Outra forma mais complexa de implementar o Endereçamento Aberto é criar uma nova função de espalhamento que 
resolva o novo conflito (também chamado de double hashing). Na prática, o que acontece nesse caso é que o vetor 
da tabela é formado por uma seqüência de funções de espalhamento auxiliares, onde a chave de entrada será o valor 
gerado pela função anterior. Esse tipo de implementação pode ser útil em casos muito específicos, com enormes
Tabela de Hash 31
quantidades de dados, mas normalmente o overhead não justifica a experiência.
Indexação Perfeita
Se tivermos uma relação fixa de registros, podemos obter uma função que indexe os itens sem que ocorra nenhuma
colisão, chamada função de espalhamento perfeita. Podemos até mesmo buscar uma função de espalhamento perfeita
mínima, que, além de não causar colisões, preenche todas as posições da tabela. As funções de espalhamento
perfeitas fazem o acesso aos dados ser O(1) no pior caso.
Existem métodos que atualizam a função de espalhamento de acordo com a entrada, de forma que nunca ocorra
colisão. O inconveniente dessa técnica é que a própria atualização da função de espalhamento causa overhead do
sistema.
Problemas e comparações com outras estruturas
Apesar das tabelas hash terem em média tempo constante de busca, o tempo gasto no desenvolvimento é
significativo. Avaliar uma boa função de espalhamento é um trabalho duro e profundamente relacionado à estatística.
Na maioria dos casos soluções mais simples como uma lista encadeada devem ser levados em consideração.
Os dados na memória ficam aleatoriamente distribuídos, o que também causa overhead no sistema. Além disso, e
mais importante, o tempo gasto na depuração e remoção de erros é maior do que nas árvore AVL, que também
podem ser levadas em conta para solução do mesmo tipo de problema.
Árvore
Árvore é uma estrutura de dados que herda as características das topologias em árvore. Conceptualmente diferente
das listas encadeadas, em que os dados se encontram numa sequência, nas árvores os dados estão dispostos de forma
hierárquica.
A árvore é composta por um elemento principal chamado raiz, que possui ligações para outros elementos, que são
denominados de galhos ou filhos. Estes galhos levam a outros elementos que também possuem outros galhos. O
elemento que não possui galhos é conhecido como folha ou nó terminal.
O número máximo de galhos em um elemento é chamado ordem da árvore. Uma árvore binária é aquela de ordem 2,
i.e., em que cada elemento possui no máximo 2 galhos.
Uma das operações importantes consiste em percorrer cada elemento da árvore uma única vez. Esse percurso,
também chamado de travessia da árvore, pode ser feito em pré-ordem (os filhos de um nó são processados após o
nó) ou em pós-ordem (os filhos são processados antes do nó). Em árvores binárias é possível ainda fazer uma
traversia em-ordem, em que se processa o filho à esquerda, o nó, e finalmente o filho à direita.
O algoritmo abaixo descreve uma travessia pré-ordem:
PercursoPreordem(nó): 
 Processa nó
 Para cada filho de nó (se houver)
 Executa recursivamente PercursoPreordem(filho) 
Outra operação, utilizada nas árvores de pesquisa é a travessia da raiz até uma das folhas. Essa operação tem um 
custo computacional proporcional ao número de níveis da árvore. O pior caso é a travessia de todos os elementos até 
a folha de nível mais baixo. A árvore balanceada, em que todas as folhas possuem o mesmo nível (com exceção de 
uma delas, que pode estar um nível acima) apresenta o melhor pior caso possível, para um certo número de nós. O 
pior pior caso apresenta-se na árvore degenerada em que cada nó possui exatamente um filho, e a árvore tem o
Árvore 32
mesmo número de níveis que de nós, assemelhando-se a uma lista ligada.
Topologia em árvore
Diagrama conceptual de uma topologia em árvore. Cada número é um nó.
Um configuração em árvore ou topologia
em árvore é uma caracterização física de
um objecto (ou seus componentes), que,
pela sua configuração, se assemelha a uma
árvore, no sentido em que as suas
ramificações tendem a convergir para uma
raíz, ou uma origem (por exemplo, árvore
genealógica).
Introduz-se, portanto, a noção de raíz e
descendência.
Em informática é vulgarmente utilizada
como topologia, ao lado de outras como
topologia em anel ou topologia em estrela.
Em programação são largamente utilizadas como estruturas de dados para resolver problemas complexos, como
indexação, por exemplo.
Nós de uma árvore
Por definição, uma árvore é constituída por nós. Um árvore vazia (sem nós) é também uma árvore.
Um nó de uma árvore é o elemento unitário da árvore. Deste nó podem derivar (descender) outros nós, designados
de nós-filho, sendo o nó actual o nó-pai.
O grau de uma árvore é o número máximo de descendentes encontrado, para cada um dos nós. Se todos os nós
derivam (no máximo) outros 2 nós, então estaremos perante uma árvore binária.
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.
Árvores Binárias 33
Árvores Binárias
Exemplo de árvore binária
Árvore binária é uma estrutura de dados caracterizada por:
•• Ou não tem elemento algum (árvore vazia).
•• Ou tem um elemento distinto, denominado raiz, com dois
apontamentos para duas estruturas diferentes, denominadas
sub-árvore esquerda e sub-árvore direita.
Perceba que a definição é recursiva e, devido a isso, muitas
operações sobre árvores binárias utilizam recursão. É o tipo de
árvore mais utilizado na computação. A principal utilização de
árvores binárias são as árvores de busca.
Definições para árvores binárias
Os nós de uma árvore binária possuem graus zero, um ou dois. Um nó de grau zero é denominado folha.
Uma árvore binária é considerada estritamente binária se cada nó da árvore possui grau zero ou dois.
A profundidade de um nó é a distância deste nó até a raiz. Um conjunto de nós com a mesma profundidade é
denominado nível da árvore. A maior profundidade de um nó, é a altura da árvore.
Uma árvore é dita completa se todas as folhas da árvore estão no mesmo nível da árvore.
Definições em teoria dos grafos
Em teoria dos grafos, uma árvore binária é definida como um grafo acíclico, conexo, dirigido e que cada nó não tem
grau maior que 3. Assim sendo, só existe um caminho entre dois nós distintos.
E cada ramo da árvore é um vértice dirigido, sem peso, que parte do pai e vai o filho.
Percursos em árvore
Existem três tipos de percursos: Percurso em InOrdem, PreOrdem e PosOrdem.
InOrdem
O algoritmo desse percurso é:
emOrdem(Struct No *n){
 if(n!=null){
 emOrdem(n->esq);
 visita(n);
 emOrdem(n->dir);
 }
}
Para a árvore acima, o percurso seria: 2, 7, 5, 6, 11, 2, 5, 4 e 9.
Árvores Binárias 34
PreOrdem
O algoritmo desse percurso é:
preOrdem(Struct No *n){
 if(n!=null){
 visita(n);
 preOrdem(n->esq);
 preOrdem(n->dir);
 }
}
Para a árvore acima, o percurso seria: 2, 7, 2, 6, 5, 11, 5, 9 e 4.
PosOrdem
O algoritmo desse percurso é:
posOrdem(Struct No *n){
 if(n!=null){
 posOrdem(n->esq);
 posOrdem(n->dir);
 visita(n);
 }
}
Para a árvore acima, o percurso seria: 2, 5, 11, 6, 7, 4, 9, 5 e 2.
Transformação de uma árvore n-ária
Uma árvore n-ária qualquer (árvore cujos nós possuem graus menoresou iguais a n) podem ser representados por
uma árvore binária. Um exemplo dessa transformação pode ser vista em [1]
Métodos para representação de árvores binárias
Uma das maneiras mais simples de representar árvores binárias em linguagens de programação é por meio de
arranjos unidimensionais (vetores). Dado um nó de índice i qualquer, os seus filhos terão índices 2i + 1 e 2i + 2 e o
seu pai terá índice piso((i - 1)/2). Essa implementação é utilizada para representar árvores completas ou quase
completas. Heaps, que são árvores binárias quase completas são implementadas na forma de um vetor de uma
maneira bastante eficiente.
Apesar da simplicidade, essa representação requer uma grande quantidade de memória contígua para o
armazenamento de árvores grandes, o crescimento desta é difícil de implementar e manter e pode haver grande
quantidade de desperdício de memória.
Árvores Binárias 35
Em uma linguagem que possua suporte a estruturas e referências (por exemplo Pascal e C), as árvores são
implementadas a partir de nós, com um, ou mais, campos para a(s) informação(ões) principal(is) e dois campos
apontadores especiais, denominados esquerda e direita, que fazem referência às sub-árvores esquerda e direita,
respectivamente. Algumas vezes, há um apontador para o pai. Em um nó do tipo folha, os campos apontadores
possuem valores especiais (nil em Pascal e NULL em C).
Referências
[1] http:/ / en. wikipedia. org/ wiki/ Image:Nary_to_binary_tree_conversion. png
Árvores AVL
Uma árvore não-AVL
Árvore AVL (ou árvore balanceada pela altura)é
uma árvore de busca binária auto-balanceada. Em tal
árvore, a altura de dois nós folha difere no máximo em
uma unidade. As operações de busca, inserção e
eliminação de elementos possuem complexidade
(no qual é o número de elementos da
árvore). Inserções e eliminações podem também
requerer o rebalanceamento da árvore, exigindo uma ou
mais rotações.
O nome AVL vem de seus criadores Georgii Adelson
Velsky e Yevgeniy Landis ,cuja primeira referência
encontra-se no documento "Algoritmos para
organização da informação" de 1962.
Características
Balanceamento
Uma árvore AVL é dita balanceada quando a diferença entre as alturas das sub-árvores não é maior do que um. Caso
a árvore não estiver balanceada é necessário seu balanceamento através da rotação simples ou rotação
Árvores AVL 36
Mesma árvore após balanceamento por altura, agora uma árvore
AVL
dupla. O balanceamento é requerido para as operações
de adição e exclusão de elementos. Para definir o
balanceamento é utilizado um fator específico para nós.
O fator de balanceamento de um nó é dado pelo seu
peso em relação a sua sub-árvore. Um nó com fator
balanceado pode conter 1, 0, ou -1 em seu fator. Um nó
com fator de balanceamento -2 ou 2 é considerado um
árvore não-AVL e requer um balanceamento por
rotação ou dupla-rotação.
Operações
Inserção
Inserção em uma árvore AVL deve ser dada pela inserção do nodo seguida de uma verificação na propriedade do
fator de balanceamento. Caso não obedeça a essa propriedade, deve-se fazer uma rotação conveniente.
Remoção
A remoção deve ser dada por uma rotação em torno do nodo a ser removido, a fim de torná-lo folha para que então
possa ser removido. Em alguns casos, após a remoção são necessárias rotações para ajustar o fator de balanceamento.
Pesquisa
O número de comparações para localizar um elemento em AVL é aproximadamente 1.44 log2 n no pior caso.
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. Uma rotação-dupla ocorre
quando um nó estiver desbalanceado e seu filho estiver inclinado no sentido inverso ao pai.
Rotação à esquerda
Em uma árvore binária, basta empurrar o nodo N para baixo e para a esquerda. O filho à direita de N o substitui, e o
filho à esquerda do filho à direita vem a ser o novo filho à direita de N. Segue pseudocódigo:
Seja Y o filho à direita de X Troque X por Y Torne o filho à esquerda de Y o
filho à direita de X.
Rotação à direita
Em uma árvore binária basta empurrar o nodo N para baixo e para a direita. O filho à esquerda de N o substitui, e o
filho à direita do filho à esquerda vem a ser o novo filho à esquerda de N. Segue pseudocódigo:
Seja Y o filho à esquerda de X Troque X por Y Torne o filho à direita de Y o
filho à esquerda de X. É interessante observar que as rotações duplas nada mais são que duas rotações
simples seguidas, independentes se à direita ou à esquerda.
Árvores AVL 37
Bibliografia
Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. Introduction to Algorithms, Second
Edition. MIT Press and McGraw-Hill, 2001. ISBN 0-262-03293-7.
Ligações externas
• Applet de uma Árvore AVL [1]
• Mais um applet de Árvore AVL [2]
• Árvores AVL no National Institute of Standarts and Technology [3]
Referências
[1] http:/ / www. csi. uottawa. ca/ ~stan/ csi2514/ applets/ avl/ BT. html
[2] http:/ / webpages. ull. es/ users/ jriera/ Docencia/ AVL/ AVL%20tree%20applet. htm
[3] http:/ / www. nist. gov/ dads/ HTML/ avltree. html
Árvores Rubro-Negras
Visualização de uma árvore rubro-negra
Árvore rubro-negra (Red-Black tree)
é uma estrutura de dados de
programação criada em 1972 com o
nome de árvores binárias simétricas.
Como as árvores binárias comuns às
rubro-negras possuem um conjunto de
operações (inserção, remoção, busca),
porém são geralmente mais eficientes
devido ao fato da rubro-negra estar
sempre balanceada. Este
balanceamento se dá justamente pela
característica que dá nome a árvore,
que vem de um bit extra em cada nodo que determina se esta é "vermelha" ou "preta" dentro do conjunto de regras
que rege a árvore. Além desde bit, cada nodo também conta com os campos dados do nodo, filho esquerdo do nodo,
filho direito do nodo e pai do nodo.
Regras da rubro-negra
Uma árvore rubro-negra estará sempre balanceada pois segue o seguinte conjunto de regras:
•• cada nodo da árvore possui um valor
•• a cada novo nodo inserido na árvore obedecerá o esquema de menor para o lado esquerdo e maior para o lado
direito.
•• a cada nodo é associado uma cor: vermelha ou preta.
•• o nodo raiz é sempre preto.
•• nodos vermelhos que não sejam folhas possuem apenas filhos pretos.
•• todos os caminhos a partir da raiz até qualquer folha passa pelo mesmo número de nodos pretos.
A cada vez que uma operação é realizada na árvore, testa-se este conjunto de propriedades e são efetuadas rotações e
ajuste de cores até que a árvore satisfaça todas estas regras.
Árvores Rubro-Negras 38
Rotações
Uma rotação é uma operação realizada na árvore para garantir seu balanceamento. Na rubro-negra pode ser feita a
direita e a esquerda, onde são alterados os nodos rotacionados.
Inserções
Ao inserir-se um elemento em uma árvore rubro-negra, esta é comparada com os elementos e alocada em sua
posição conforme a regra 2. Ao inserir um elemento ele é sempre da cor vermelha (exceto se for o nodo raiz). A
seguir a árvore analisa se o antecessor da folha. Se este for vermelho será necessário alterar as cores para garantir a
regra 6.
Remoções
Existem dois tipos de remoção em uma árvore:
Remoção efetiva
Com as operações de rotação e alteração de cor, remove-se o nodo e estabelece-se as propriedades da árvore.
Remoção preguiçosa
Esta remoção marca um nó como removido, mas efetivamente não o retira. Sendo desta maneira nenhuma alteração
é efetuada na árvore, porém são necessários novos mecanismos de busca e inserção para que reconheçam o nó como
"ausente".
Bibliografia
• Mathworld: Red-Black Tree [1]
• San Diego State University: CS 660: Red-Black tree notes [2], por Roger Whitney
• Thomas H. Cormen,Charles E. Leiserson, Ronald L. Rivest, e Clifford Stein. Introduction to Algorithms, Second
Edition. MIT Press and McGraw-Hill, 2001. ISBN 0-262-03293-7 . Chapter 13: Red-Black Trees, pp. 273–301.
Ligações externas
Demos
• Red/Black Tree Demonstration [3], um demo interativo em Java
• Red-Black Tree Animation [4]
• aiSee: Visualization of a Sorting Algorithm [5], uma animação em gif (200 Kb)
• Red-Black Tree Demonstration [6],um demo em Java criado por David M. Howard
• AVL Tree Applet [2]
Árvores Rubro-Negras 39
Implementações
• Efficient implementation of Red-Black Trees [7]
• RBT: A SmallEiffel Red-Black Tree Library [8]
• libredblack: A C Red-Black Tree Library [9]
• Red-Black Tree C Code [10]
• Red-Black Tree Java implementation in java.util.TreeMap [11]
• DragonFlyBSD VM subsystems utilize Red-Black trees [12]
Referências
[1] http:/ / mathworld. wolfram. com/ Red-BlackTree. html
[2] http:/ / www. eli. sdsu. edu/ courses/ fall95/ cs660/ notes/ RedBlackTree/ RedBlack. html#RTFToC2
[3] http:/ / www. ececs. uc. edu/ ~franco/ C321/ html/ RedBlack/ redblack. html
[4] http:/ / www. ibr. cs. tu-bs. de/ lehre/ ss98/ audii/ applets/ BST/ RedBlackTree-Example. html
[5] http:/ / www. aisee. com/ anim/ maple. htm
[6] http:/ / web. archive. org/ 20060210122840/ geocities. com/ dmh2000/ articles/ code/ red-blacktree. html
[7] http:/ / eternallyconfuzzled. com/ tuts/ redblack. html
[8] http:/ / efsa. sourceforge. net/ archive/ durian/ red_black_tree. htm
[9] http:/ / libredblack. sourceforge. net/
[10] http:/ / web. mit. edu/ ~emin/ www/ source_code/ red_black_tree/ index. html
[11] http:/ / www. javaresearch. org/ source/ jdk142/ java/ util/ TreeMap. java. html
[12] http:/ / dragonflybsd. org
Árvores B
Exemplo de Árvore B
Árvore B ou B-Tree são estruturas de dados
muito utilizadas em banco de dados e
sistema de arquivos.
Para inserir ou remover variáveis de um nó,
o nó não poderá ultrapassar sua ordem e
nem ser menor que sua ordem dividida por
dois. Árvores B não precisam ser
rebalanceadas como são freqüentemente as
árvores de busca binária com Árvore AVL.
Árvores B têm vantagens substanciais em
relação a outros tipos de implementações quanto ao tempo de acesso e pesquisa aos nós.
O criador das árvores B, Rudolf Bayer, não definiu claramente de onde veio o B das árvores B. Ao que parece, o B
vem de balanceamento onde todos os nós da árvore estão em um mesmo nível. Também é possível que o B tenha
vindo de seu sobrenome Bayer, ou ainda do nome da empresa onde trabalhava Boeing, no Boeing Scientific
Research Labs.
Introdução
O estudo das diferentes estruturas de dados vistas anteriormente foi realizado supondo um custo de acesso aos dados
uniforme e da mesma ordem de grandeza que as demais operações. Porém, na prática, isso nem sempre é o caso. Em
sistemas computacionais atuais, a memória é organizada hierarquicamente, sendo o custo de acesso inversamente
proporcional ao custo financeiro. Por ordem decrescente de velocidade de acesso (e por ordem crescente de custo
financeiro), temos: registros internos do processador, memória cache, memória principal (RAM), memória
secundária (disco rígido), memória externa (mídia ótica, fitas).
Árvores B 40
Um exemplo é quando é preciso representar e manipular através de buscas, inserções e remoções, uma quantidade de
dados tal que a capacidade da memória principal disponível não é suficiente. Neste caso, por razões econômicas (o
custo de expansão da memória principal) ou tecnológicas (o maior tamanho de memória principal que o sistema
operacional pode gerenciar), torna-se necessário recorrer a memória secundário para armazenar parte dos dados.
Historicamente, o tempo de acesso a memória secundária (discos ou fitas) sempre foi muito superior ao de acesso a
memória principal. Nas tecnologias atuais, o fator relacionando esses dois tempos torna entre e : o tempo
de um acesso em memória secundária é equivalente ao tempo de execução de 10.000 a 100.000 instruções. Em geral,
os sistemas gerenciadores de bancos de dados devem operar vários usuários em paralelo. Supondo uma média de 50
usuários concorrentes, e um tempo médio de acesso ao disco de 10ms, o número médio de acessos que um usuário
pode fazer é de 2 por segundo.
Por exemplo, supõe que você deve elaborar um sistema de gerenciamento de um banco de dados que tem cerca de
25.000.000 (vinte-e-cinco milhões) de registros. Cada registro tem um tamanho de 1kB e uma chave de 4 bytes
(supondo a existência de uma relação de ordem entre as chaves). A quantidade total de memória necessária é de 25
GB (vinte-e-cinco gigabytes). Se for usada uma árvore binária balanceada, por exemplo uma árvore rubro-negra, os
números médio e máximo de acessos à memória secundária numa busca seria 48 ( )$. Os
tempos médios e máximos de busca seriam portanto 12s e 24s. Em certas aplicações, esses números podem não ser
aceitáveis.
As árvores B são um tipo de árvores de busca que foram projetadas para minimizar o número de acessos à memória
secundária. Como o número de acessos à memória secundária depende diretamente da altura da árvore, as árvores B
foram projetadas para ter uma altura inferior às árvores rubro-negras ou AVL, para um dado número de chaves. Para
manter o número de registros armazenados e, ao mesmo tempo, diminuir a altura, uma solução é aumentar o grau de
ramificação da árvore (o número máximo de filhos que um nó pode ter). Assim árvores B são árvores de busca que
possuem um grau de ramificação geralmente muito maior que 2. Além disso, a cada nó de uma árvore B são
associados mais de um registro de dados: se o grau de ramificação de um nó for , este pode armazenar até 
registros. A figura abaixo mostra um exemplo de árvore B, com grau de ramificação dos nós de até 4.
Em geral o grau de ramificação de uma árvore B é determinado pelas características físicas da memória secundária
empregada, pois memórias secundárias usualmente têm uma unidade atômica de leitura/escrita. Para armazenar uma
árvore B, cada nó da árvore será armazenado numa unidade de memória secundária. Por exemplo, supondo que a
unidade tem uma capacidade de 4kB e que seu endereço seja codificado sobre 4 bytes. O maior grau de ramificação
possível neste caso é denotado e é tal que: , ou seja .
Esse grau de ramificação é muito perto do das árvores balanceadas. A altura do árvore B correspondente não será
significativamente inferior a altura que teria uma árvore binária correspondente.
Uma alternativa é, no lugar de armazenar o registro inteiro no nó da árvore B, colocar a chave e uma referência a um
unidade de disco que contem essa informação. Em nosso exemplo, o tamanho de uma referência é 4 bytes. Supondo
que o tamanho da chave seja também de 4 bytes, o grau de ramificação é tal que:
, ou seja .
Neste caso, cada nó armazena 341 chaves com a referência ao registro correspondente. A raiz pode ter até 342 filhos
e 116964 netos. A capacidade desta árvore B é referências.
Supondo que a raiz sempre fica em memória principal, são necessários, no máximo, dois acessos a memória
secundária para achar uma chave, e de um terceiro acesso para ler o registro correspondente. Utilizando os
parâmetros da discussão acima, o tempo de espera do usuário devido as transações com a memória secundária cai
para 1,5s (a comparar com as estimativas de até 24s com uma implementação por árvores rubro-negra).
Árvores B 41
Estrutura do nó
Nós em árvores B, também denominado páginas, geralmente são representados por um conjunto de elementos
apontando para seus filhos. Alguns autores consideram a ordem de uma árvore B como sendo a quantidade de
registros que a página pode suportar. Outros consideram a ordem como a quantidade de campos apontadores. Todo
nó da árvore tem um mínimo de registros definido pela sua ordem, que é a metade da ordem, arredondando-se para
baixo, caso a árvore seja de ordemímpar, exceto a raiz da árvore, que pode ter um mínimo de um registro. Por
exemplo, os nós de uma árvore de ordem 5, podem ter, no mínimo registros, ou seja, dois registros. A
quantidade de filhos que um nó pode ter é sempre a quantidade de registros do nó mais 1 (V+1). Por exemplo, se um
nó tem 4 registros, este nó terá obrigatoriamente 5 apontamentos para os nós filhos.
Algoritmos
Inserção
1.1. Primeiro, pesquise a posição onde este nó será incluído. Então, insira o valor dentro do nó.
2.2. Se nenhum nó ficou errado, acima ou abaixo da ordem div 2, o processo é terminado.
3.3. Se algum nó ficar acima da ordem, dividimos o nó, o valor central do nó dividido sobe para a posição do pai,
continuando assim recursivamente por toda a árvore. Se o nó estourar na raiz, então é criado um novo nó raiz
(podendo ter um único elemento).
Exclusão
1.1. Primeiro, busque um valor a ser excluído. Então, remova-o de dentro de um nó.
2.2. Se nenhum nó teve problema, o processo é terminado.
3.3. Se algum nó estiver errado, então há duas possibilidades:
1.1. Se o nó ao lado do nó errado pode transferir um ou mais de seus nós filho ao nó atual, então o nó atual voltará
ao normal. Após ter atualizado os valores da separação do pai e dos dois filhos, o processo é terminado.
2.2. Se o nó ao lado do nó errado não tem um filho extra porque está no limite mais baixo, então ambos os nós
serão fundidos em um único nó. Continuando até que o nó atual esteja normal.
Exercício
Seja uma árvore B de altura e grau máximo de ramificação . Dar, em função de e , o número
máximo de referências que essa árvore B pode armazenar.
Ligações externas
• Animação de uma simples árvore B [1].
• Applet de uma B-Tree [2]
Esta página é somente um esboço.
Ampliando-a você ajudará a melhorar o Wikilivros.
Árvores B 42
Referências
[1] http:/ / www. cse. ohio-state. edu/ ~bondhugu/ acads/ 234-tree/ index. shtml
[2] http:/ / slady. net/ java/ bt/
Estruturas para classes de equivalência
Estruturas para classes de equivalência
Introdução
Diversos problemas podem ser modelados através do cálculo de classes de equivalência (uma definição formal desse
conceito é apresentada logo em seguida). Um exemplo famoso é aquele de determinar os componentes conexos de
um grafo. Um grafo é um conjunto de vértices que podem ser conectados dois a dois por arestas. Como determinar
se, dado o conjunto das arestas, existe um caminho entre dois vértices? Se considerarmos dois vértices como
equivalentes quando existe um caminho entre os dois, então uma solução desse problema consiste em determinar se
dois vértices fazem parte da mesma classe de equivalência.
Definições
Uma relação binária sobre um domínio é uma relação de equivalência se satisfaz as seguintes
propriedades
1. ( é simétrica);
2. ( é reflexiva);
3. ( é transitiva).
Seja um elemento do domínio, a classe de equivalência de é o conjunto dos
elementos relacionados com .
Objetivo
O cliente do tipo abstrato de dados manipula valores de um determinado domínio que nomeamos D. O objetivo é
definir um tipo abstrato de dados que permita representar e manipular eficientemente classes de equivalência que
evoluem dinamicamente. Inicialmente cada classe de equivalência é constituída por um único elemento do domínio
D, d. O nome de cada classe é d. Queremos operações para unir classes, e determinar o nome da classe de
equivalência de um elemento.
O tipo abstrato de dados possuirá três operações: 1)construtor: cria as classes. 2)Find: determina o nome da classe de
equivalência de um elemento qualquer de D. 3)Uniao: une duas classes de nomes conhecidos.
O construtor cria uma classe de equivalência para cada elemento d distinto de D. Pós-Condição - Cada classe tem
apenas um elemento, d. O nome da classe de d é d.
Find
dado d de D, retorna o nome da classe de d.
Uniao
Dadas duas classes de nomes d1 e d2, realiza a união das duas classes de equivalência, adotando d1 ou d2
como nome da nova classe. As classes unidas deixam de existir.
Estruturas para classes de equivalência 43
Apresentação das soluções
Os algoritmos e estruturas de dados que provêm implementação eficientes desse tipo abstrato de dados são
conhecidos como algoritmos Union-Find (União-Busca), pelo tipo de operações que são providas. Outros nomes
encontrados são disjoint sets (conjuntos disjuntos) e dynamic equivalence relations (relações de equivalência
dinâmicas).
Existe basicamente duas estruturas de dados para implementar o tipo abstrato União-Busca: a baseada em listas, e a
baseada em árvores. A estrutura de dados linear, baseada em listas encadeadas, é mais apropriada para aplicações
onde o número de operações de união é pequeno com relação ao número de aplicações de busca. Em contrapartida, a
estrutura de dados ramificada, baseada em árvores, é mais eficiente quando o número de união é proporcionalmente
mais elevado que o número de buscas. A estrutura de dados baseada em árvores é fácil de implementar como um
vetor, sendo adotada por muitos autores. Além disso permite realizar as operações prasticamente em tempo
constante.
Fontes e Editores da Página 44
Fontes e Editores da Página
Objetivo  Fonte: http://pt.wikibooks.org/w/index.php?oldid=213130  Contribuidores: Atoj, Helder.wiki, 1 edições anónimas
O que é um Algoritmo?  Fonte: http://pt.wikibooks.org/w/index.php?oldid=249470  Contribuidores: Helder.wiki, Jorge Morais, 6 edições anónimas
Para que servem os algoritmos?  Fonte: http://pt.wikibooks.org/w/index.php?oldid=233099  Contribuidores: Jorge Morais, 3 edições anónimas
Sintaxe  Fonte: http://pt.wikibooks.org/w/index.php?oldid=213132  Contribuidores: Araruna, Helder.wiki, Jorge Morais, 3 edições anónimas
Recursividade  Fonte: http://pt.wikibooks.org/w/index.php?oldid=213131  Contribuidores: Araruna, Helder.wiki, Jorge Morais, Marcos Antônio Nunes de Moura, Master, 1 edições anónimas
Algoritmos de Ordenação  Fonte: http://pt.wikibooks.org/w/index.php?oldid=203734  Contribuidores: Master, 2 edições anónimas
Selection e Insertion  Fonte: http://pt.wikibooks.org/w/index.php?oldid=203747  Contribuidores: Giro720
O que são estruturas de dados?  Fonte: http://pt.wikibooks.org/w/index.php?oldid=112198  Contribuidores: Helder.wiki, Jorge Morais, Master, 2 edições anónimas
Abstração de Dados  Fonte: http://pt.wikibooks.org/w/index.php?oldid=211064  Contribuidores: Master, 1 edições anónimas
Vetores e Matrizes  Fonte: http://pt.wikibooks.org/w/index.php?oldid=260285  Contribuidores: Abacaxi, Helder.wiki, Infroger, Jorge Morais, LUISKISKIS, Master, Raylton P. Sousa, 16
edições anónimas
Estruturas  Fonte: http://pt.wikibooks.org/w/index.php?oldid=203740  Contribuidores: Master
Listas  Fonte: http://pt.wikibooks.org/w/index.php?oldid=254393  Contribuidores: Abacaxi, Master, RenatoResende, 1 edições anónimas
Pilhas  Fonte: http://pt.wikibooks.org/w/index.php?oldid=250754  Contribuidores: Abacaxi, Master, 7 edições anónimas
Filas  Fonte: http://pt.wikibooks.org/w/index.php?oldid=238486  Contribuidores: Master, 1 edições anónimas
Lista encadeada  Fonte: http://pt.wikibooks.org/w/index.php?oldid=235378  Contribuidores: Master, 2 edições anónimas
Tabela de Hash  Fonte: http://pt.wikibooks.org/w/index.php?oldid=203748  Contribuidores: Master
Árvore  Fonte: http://pt.wikibooks.org/w/index.php?oldid=225705  Contribuidores: Helder.wiki, Master, 2 edições anónimas
Árvores Binárias  Fonte: http://pt.wikibooks.org/w/index.php?oldid=248681  Contribuidores: Master, 2 edições anónimas
Árvores AVL  Fonte: http://pt.wikibooks.org/w/index.php?oldid=203736  Contribuidores: Master
Árvores Rubro-Negras  Fonte: http://pt.wikibooks.org/w/index.php?oldid=263992  Contribuidores: Master, Rotlink, 1 edições anónimas
Árvores B  Fonte: http://pt.wikibooks.org/w/index.php?oldid=245364  Contribuidores: Abacaxi, Master
Estruturas para classes de equivalência  Fonte: http://pt.wikibooks.org/w/index.php?oldid=248709

Continue navegando