Buscar

aula07

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 6 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 6 páginas

Prévia do material em texto

7ºAula
ÁRVORES B
Objetivos de aprendizagem
Ao término desta aula, vocês serão capazes de: 
• compreender como funciona uma Árvore B;
• entender as operações possíveis em uma Árvore B.
Olá,
Nesta aula, vamos finalizar os estudos sobre as Árvores. 
Estudaremos um tipo de árvore que é muito utilizado nos 
sistemas de armazenamento. Trata-se das Árvores B, onde a sua 
definição e o seu processo de inserção serão o assunto principal 
da nossa aula.
Leiam atentamente esta aula e façam os exercícios. Se 
enfrentarem alguma dúvida, estaremos a sua disposição na área 
do aluno.
Bons estudos!
47
Estrutura de Dados II 46
1. 
Seções de estudo
Introdução a Árvores B
2. Operações em uma Árvore B
1 - Introdução a Árvores B
Vocês devem saber que, normalmente, armazenamos 
nossos dados para uso futuro em dispositivos de 
armazenamento secundário de dados. Até o surgimento dos 
Discos de Estado Sólido (SSD), que usam a mesma tecnologia 
presente nos pendrives e cartões de memória, os dispositivos 
que faziam esse papel nos computadores eram os discos 
rígidos.
 Dentro dos discos rígidos temos uma série de pratos, 
que funcionam de forma análoga a um disco de vinil: uma 
agulha percorre os setores do disco e lê os dados armazenados 
no setor. 
Figura 1 - Parte interna de um disco rígido. Fonte: Disponível em: < https://www.
2018.
Apesar dos avanços na tecnologia, a velocidade dos 
discos rígidos sempre foi um gargalo nos computadores. 
Vejam esse comparativo:
Dispositivo Ta a de Transferência(em megabytes por segundo)
HD com conector IDE 133
HD com conector SATA 150 150
HD com conector SATA II 300
SSD mais simples 550
SSD mais avançado 2000
Memória RAM DDR2-800 6400
Memória RAM DDR3-1333 10664
Memória RAM DDR4-2133 17064
Fonte: Dados extraídos dos sites: < https://www.tecmundo.com.br/placa-
tecmundo.com.br/hardware/102277-hd-comum-hd-alta-velocidade-descubra-
das-mem%C3%B3rias-ram-r34433/ >. Acesso em: 23 set. 2018.
Assim, os cientistas da computação sempre procuraram 
formas de otimizar o acesso aos dados. Uma dessas tentativas 
foi criar uma árvore onde o seu objetivo era minimizar a 
quantidade de acesso aos dados. A solução consiste em 
armazenar um conjunto de dados em cada nó da árvore. Cada 
dado possui um ponteiro para a árvore com valores menores 
do que o seu e um ponteiro para a árvore com valores maiores 
do que o seu. Esse é o fundamento básico da Árvore B.
A figura 2 mostra uma árvore B. O nó M é a sua raiz. 
Assim como a árvore binária, temos ponteiros para as 
subárvores maiores e menores que o dado. Mas, a diferença 
é que na árvore binária os ponteiros são em relação ao nó, 
pois cada nó armazena um único dado. No caso da árvore B, 
os ponteiros são em relação ao dado, não em relação ao nó. 
Como o nó raiz só tem um dado, temos apenas dois ponteiros.
Na subárvore direita temos os valores que são maiores 
que M. O nó raiz dessa subárvore tem três dados: Q, T e X. 
Nesse nó temos quatro ponteiros: Os nós que são menores 
que Q, os nós que estão entre Q e T, os nós que estão entre T 
e X, e os nós que são maiores que X.
Para buscar um dado precisamos percorrer os dados 
desse nó para procurar se o dado está nesse nó ou deve estar 
em algum dos ponteiros para uma subárvore. Por exemplo, se 
estamos procurando a letra R, começamos pela raiz. Seguimos 
o caminho pela subárvore direita de M. Depois, vasculhamos 
todos os dados da raiz da subárvore direita de R. Seguimos 
pelo ponteiro que está entre T e X. Chegamos então, ao nó 
com a letra R. 
percorridos para chegar a letra R. Fonte: (CORMEN et. al, 2012, p. 352).
Além disso, visando a otimização da árvore, existe 
uma quantidade mínima de dados a ser armazenados, e 
uma quantidade máxima, que é equivalente a 2x-1, sendo x 
a quantidade mínima de dados a ser armazenados. Assim, 
cada nó pode ter de x+1 a 2x filhos. Uma árvore B, em que 
fixamos a quantidade mínima de dados como 2, pode ter de 
1 a 3 dados (que também são chamados de chaves) e de 2 a 
4 filhos.
Formalmente, podemos definir uma árvore B como uma 
árvore T, que possui uma raiz (denominado de T.raiz), que 
tem as seguintes características:
• Grau mínimo da árvore t, que determina os limites 
inferiores e superiores da quantidade de chaves do 
nó.
 Todo nó (exceto a raiz) tem pelo menos t-1 chaves.
 Todo nó (exceto a raiz) tem pelo menos 2t-1 chaves.
• Cada nó x tem as seguintes informações:
 A quantidade n de chaves (dados) armazenados, 
denominado de x.n.
 As chaves, denominados de x.chave, que armazena 
de forma crescente os dados. Os dados estão dispostos de 1 
até n.
48
47
• Um atributo booleano folha (x.folha) que indica se 
esse nó é folha. Se configurado como verdadeiro, o 
nó é folha. Se for falso, ele possui filhos.
• Cada nó interno x contêm n+1 ponteiros, 
denominados de x.c[1] até x.c[n+1], que apontam 
para os seus filhos.
• As chaves separam os intervalos armazenados em 
cada subárvore.
• Toda folha tem a mesma profundidade, que é a 
altura h da árvore.
• Uma árvore B pode ter as seguintes variações:
• Árvore 2-3-4: é uma árvore B mais simples, onde t 
= 2. Assim, cada nó pode ter apenas 2, 3 ou 4 filhos.
• Árvore B*: é um tipo de árvore B que exige que cada 
nó esteja 2/3 completo.
• Árvore B+: nesse tipo de árvore, ela armazena os 
dados somente nas folhas. A raiz e os nós internos 
só armazenam ponteiros.
Mas, por que a árvore B é útil para a nossa situação? 
Vamos para um exemplo. Suponhamos que queremos 
armazenar um bilhão de chaves em uma árvore. Enquanto 
que em uma árvore binária, poderemos ter uma altura de no 
mínimo 23 níveis, em uma árvore B que armazena no máximo 
1000 chaves, poderemos ter uma árvore de 3 níveis. E terá 
espaço de sobra.
Figura 3 - Árvore B com mais de 1 bilhão de chaves, com a sua altura 3 (ou 2, 
(CORMEN et. al, 2012, p. 355).
Agora que você sabe o que é uma árvore B e o seu uso, 
vamos para as operações que são realizadas em uma árvore B.
2 - Operações em uma Árvore B
Assim como em toda árvore, a árvore B tem operações 
de manipulação e busca dos dados. Nesta aula, vamos 
apresentar como funciona os algoritmos de busca e inserção 
de dados em uma árvore B. Além disso, vamos abordar como 
criar uma árvore B vazia.
2.1 - Buscando dados em uma 
árvore B
A busca de dados em uma árvore B segue o seguinte 
fluxo, dado a raiz da árvore e o valor a ser buscado:
• Percorre todos os valores presentes no nó, até 
que encontramos o índice i do primeiro valor que 
não seja menor que o valor que estamos buscando 
dentro do nó.
• Ao pararmos, vamos verificar se o índice i se refere 
ao valor que estamos procurando. Se for, retornamos 
o nó e o respectivo índice.
• Se não for o valor que estamos procurando, 
verificamos se o nó é folha. Se for, indica que o valor 
não foi encontrado na árvore. Retornamos NULO;
• Se não for um nó folha, a busca prossegue no filho 
que se refere apontado pelo ponteiro do índice i da 
árvore.
A seguir, apresentamos o pseudocódigo da operação de 
busca em uma árvore B.
funcao busca(x: *TArvore, k: inteiro): 
*TArvore, inteiro
declare
 i : inteiro
inicio
 i <- 1
 enquanto (i <= x.n E k > x.chave[i]) faca
 i <- i + 1
 fimenquanto
 se (i <= x.n E k = x.chave[i] entao
 // Achou
 retorne (x, i)
 senao
 se (x.folha) entao
 // Se nao achou o valor e é folha, 
nao temos
 retorne NULO
 senao
 //Lê um filho do nó
 leia-disco(x.c[i])
 retorne busca(x.c[i], k)
 fimse
 fimse
fimalgoritmo
Agora, vamos mostrar como funciona o processo de 
criação de uma árvore B.
2.2 - Criando uma árvore B
Para criar uma árvore B seguimos os seguintes passos:
• Alocamos um novo nó x.
• Marcamos esse novo nó x como folha.
• Indicamos o seu número de dados presentes como 
0, pois não temos nenhum dado nessa árvore.
• Escrevemos esse nó no disco e marcamos ele como 
a raiz da árvore.
O pseudocódigo desta operação demonstramos a seguir:
procedimento criarArvoreB()
declarex: *TArvore
início
 x <- alocaNo()
 x.folha <- VERDADEIRO
 x.n <- 0
 escreve-disco(x)
 T.raiz <- x
fimprocedimento
2.3 - Adicionando nós a árvore
Devido à natureza de uma árvore B, a operação de 
49
Estrutura de Dados II 48
inserção não é tão trivial, pois precisamos adicionar os valores 
a um nó já existente, para respeitarmos a regra de número 
mínimo e máximo de valores que estão em uma árvore B. 
Basicamente, o processo consiste em buscar em qual nó 
deve ser inserido o novo valor. Se o nó que for escolhido 
como local do novo valor estiver cheio, devemos dividir os 
valores do nó em dois, escolhendo um valor mediano. Esse 
valor mediano é promovido a condição de pai dos dois subnós. 
Vale lembrar que se o nó onde o dado será promovido estiver 
cheio, devemos fazer a separação da mesma forma.
Esse processo se chama de repartição do nó. Esse 
processo consiste em receber um nó interno x não cheio 
e um índice i que aponta para um nó cheio de x. Esse 
procedimento divide esse filho apontado pelo nó x.c[i] em 
dois. Detalhadamente, podemos definir esse processo nos 
seguintes passos:
• Alocamos um novo nó z.
• Declaramos uma nova variável y, que recebe o 
ponteiro x.c[i]. Nesse caso, y tem todos os valores 
do nó a ser repartido.
• z recebe a indicação se y é ou não é folha e tem o 
seu valor n indicado com a quantidade mínima de 
nós admitidos.
• Depois, percorremos os valores de chave de y nas 
posições 1+t a t-1 e preenchemos os valores 1 a t-1 
do nó z. Por exemplo, se t for 4, o nó z recebe os 
valores das posições 5 a 7 do nó y.
• Se y não for folha, percorremos os valores dos 
ponteiros das posições t+1 até 2t de y e passamos 
para o nó z, tornando os valores acima do nó médio 
como sendo filhos de z. Em uma árvore de t = 4, o 
nó z recebe os ponteiros da posição 5 a 8 do array 
c do nó y.
• Em seguida, atualizamos a quantidade de valores do 
nó y como t-1.
• Depois, atualizamos os ponteiros do nó x, colocando 
os ponteiros que estarão após o valor a ser 
promovido na próxima posição. Assim, o ponteiro 
c[5] será alocado na posição c[6], o ponteiro c[6] 
ficará na posição c[7], e assim sucessivamente. Em 
seguida, colocamos o ponteiro c[i+1] no valor do nó 
z, passando a apontar para z.
• Em seguida, fazemos essa operação de forma análoga 
com os valores das chaves do nó x, postergando eles 
para a próxima posição. Depois colocamos o valor 
médio do nó filho cheio entre as chaves do nó x. 
Assim, promovemos ele a condição de “pai” dos 
nós y e z.
• Depois, atualizamos a quantidade de nós de x, e 
escrevemos os nós x, y e z dentro do disco.
A seguir, apresentamos o código dessa operação:
procedimento divideNo(x: *TArvore, i: 
inteiro)
declare
 z, y: *TArvore
 j : inteiro
inicio
 z <- alocaNo()
 y <- x.c[i]
 z.folha <- y.folha
 z.n <- t - 1
 
 para i de 1 ate (t - 1) faca
 z.chave[j] <- y.chave[j+t]
 fimpara
 se (nao(y.folha)) entao
 para j de 1 ate t entao
 z.c[j] <- y.c[j+t]
 fimpara
 fimse
 y.n <- t-1
 
 para j de (x.n+1) ate i+1 passo -1 faca
 x.c[j+1] <- x.c[j]
 fimpara
 x.c[i+1] <- z
 para j de x.n ate i passo -1 faca
 x.chave[j+1] <- x.chave[j]
 fimpara
 x.chave[i] <- y.chave[t]
 
 x.n <- x.n +1
 escreva-disco(y)
 escreva-disco(z)
 escreva-disco(x)
fimalgoritmo 
t=4. A chave mediana S é promovida à condição de pai dos novos subnós. Fonte: 
(CORMEN et. al., 2012, p. 359).
Agora que mostramos como funciona a divisão do nó, 
vamos mostrar como funciona o algoritmo de inserção. Ele 
consiste em dois procedimentos. O primeiro é o procedimento 
InsereArvore, que recebe uma chave k, um ponteiro T para a 
árvore. Esse procedimento segue os seguintes passos:
• r recebe a raiz da árvore.
• Verifica se a raiz está cheia. Se estiver cheia, criamos 
um nó s e dividimos o nó raiz em dois, usando o 
procedimento divideNo, para colocar o nó mediano 
no novo nó s e dividir o nó em dois. Depois 
chamamos o procedimento auxiliar insereNaoCheio 
usando o nó s.
• Se não estiver cheio chamamos o procedimento 
insereNaoCheio usando o nó r.
O procedimento insereNaoCheio abordaremos a 
seguir. Agora, vamos mostrar como é o pseudocódigo do 
procedimento InsereArvore:
procedimento InsereArvore(T: *Arvore, k: 
50
49
inteiro)
declare
 r, s: *TArvore
inicio
 r <- T.raiz
 se r.n = (2t-1) entao
 #Cria o nó s e divide a raiz
 s <- alocaNo()
 T.raiz <- s
 s.folha <- FALSO
 s.n <- 0
 s.c[1] <- r
 divideNo(s,1)
 insereNaoCheio(s,k)
 senao
 insereNaoCheio(r,k)
 fimse
fimalgoritmo
com t=4. A chave mediana S é promovida à condição de pai dos novos subnós e de 
Al., 2012, p. 361).
O procedimento insereNaoCheio faz a inserção 
propriamente dita da chave k na árvore. Esse procedimento 
recebe um ponteiro para um nó da árvore, denominado de x e 
o valor “k” a ser inserido. Ela segue os seguintes passos:
• Verifica se o nó x é folha. Se for, o procedimento 
coloca os valores das chaves que são maiores que 
k nas posições subsequentes a atual. Logo, um 
dado que estava na posição 2 passa a posição 3, um 
dado que estava na posição 3 ficará na posição 4, e 
assim sucessivamente. Esse processo ocorre até que 
todas as chaves estejam percorridas ou quando é 
encontrado uma chave menor que o valor k. O valor 
k é inserido na posição i+1 após o percurso pelos 
valores do nó. Depois, o valor n de x é atualizado.
• Se o nó não for folha, o procedimento procura o 
próximo nó filho a ser lido pelo procedimento. 
Assim, o algoritmo percorre os valores do nó x até 
quando encontrarmos um valor que seja menor que 
o valor “k” a ser inserido. Depois lemos a posição 
do ponteiro c[i] de x, e verificamos a necessidade de 
dividir o nó apontado por x.c[i]. Se for, dividimos 
esse nó chamando o método divideNo. Em seguida, 
verificamos em qual subárvore seguir, atualizando o 
valor de i;
• Finalmente, chamamos o mesmo procedimento 
recursivamente para o nó apontado pelo ponteiro 
x.c[i].
A seguir, mostraremos o pseudocódigo deste 
procedimento.
procedimento insereNaoCheio(x: *TArvore, k: 
inteiro)
declare
 i : inteiro
inicio
 i <- x.n
 se (x.folha) entao
 enquanto i >= 1 e k < x.chave[i]
 x.chave[i+1] <- x.chave[i]
 i <- i-1
 fimenquanto
 x.chave[i+1] <- k
 x.n <- x.n + 1 //Atualiza a qtde n
 escreva-disco(x)
 senao
 enquanto i >= 1 e k < x.chave[i]
 i <- i-1
 fimenquanto
 i <- i+1
 leia-disco(x.c[i])
 se x.c[i].n = 2t-1 entao
 //No cheio - divide
 divideNo(x, i)
 se k > x.chave[i] entao
 i <- i + 1
 fimse
 fimse
 
 insereNaoCheio(x.c[i], k)
 fimse 
fimalgoritmo
E com isso, finalizamos a nossa aula. Na próxima aula, 
vamos mostrar como funciona a compactação de arquivos. 
Até lá!
Retomando a aula
Chegamos ao nal da nossa sétima aula. Vamos 
relembrar?
1 - Introdução a Árvores B
Nessa seção, vimos que uma árvore B é uma árvore T, que 
possui uma raiz (denominado de T.raiz), que tem as seguintes 
características: Grau mínimo da árvore t, que determinam os 
limites inferiores e superiores da quantidade de chaves do nó, 
sendo que todo nó (exceto a raiz) tem pelo menos t-1 chaves 
e tem pelo menos 2t-1 chaves; Nesta árvore cada nó x tem 
as seguintes informações: A quantidade n de chaves (dados) 
armazenados, denominado de x.n; as chaves denominados 
de x.chave, que armazena de forma crescente os dados. Os 
dados estão dispostos de 1 até n, e um atributo booleano 
folha (x.folha) que indica se esse nó é folha. Se configurado 
como verdadeiro, o nó é folha. Se for falso, ele possui filhos. 
51
Estrutura de Dados II 50
Cada nó interno x contêm n+1 ponteiros, denominados de 
x.c[1] até x.c[n+1], que apontam para os seus filhos; as chaves 
separam os intervalos armazenados em cada subárvore e toda 
folhatem a mesma profundidade, que é a altura h da árvore.
2 - Operações em uma Árvore B
Nesta aula, aprendemos como funcionam os principais 
algoritmos de manipulação de dados em uma árvore B, 
que são o algoritmo de busca de um dado e o algoritmo de 
inserção de um dado.
CORMEN, Thomas H.; et. al.. Algoritmos: teoria e 
prática. Rio de Janeiro: Campus, 2012.
KNUTH, Donald Ervin. The art of computer programming. 
3. ed. Amsterdam: Addison-Wesley, 1998.
SZWARCFITER, Jayme Luiz; MARKENZON, 
Lilian. Estruturas de dados e seus algoritmos. 2. ed. Rio de Janeiro: 
LTC, 1994.
TENENBAUM, Aaron M.; AUGENSTEIN, Moshe 
J.; LANGSAN, Yedidyah. et al. Estruturas de dados usando 
C. São Paulo: Pearson Makron Books; São Paulo: Makron 
Books do Brasil; São Paulo: McGraw-Hill, 2013.
ZIVIANI, Nivio. Projeto de algoritmos: com 
implementação em PASCAL e C. 3. ed. São Paulo: Cengage 
Learning, 2011.
Vale a pena ler
FEOFILOFF, Paulo. Árvores B (B-trees). USP, 2018. 
Disponível em: <https://www.ime.usp.br/~pf/estruturas-
de-dados/aulas/B-trees.html>. Acesso em: 23 set. 2018.
GALLES, David. B Tree Visualization (Simulador de 
Árvore B). USF, s.d. Disponível em: <https://www.cs.usfca.
edu/~galles/visualization/BTree.html>. Acesso em: 23 set. 
2018. 
Vale a pena acessar
Vale a pena
Minhas anotações
52

Outros materiais