Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
VITRIA 2011
SUMRIO
Captulo I Ordenao ........................................................................................................3 I.1 Introduo ....................................................................................................................3 I.2 Caractersticas de arquivos .........................................................................................4 I.3 Anlise de Algoritmos ..................................................................................................4 I.4 Medidas de tempo de execuo de um programa .......................................................5 I.4.1 Como calcular o tempo que um algoritmo leva para ser executado? ...................5 I.5 Notao O ....................................................................................................................7 I.6 Exerccios ..................................................................................................................10 I.7 Exerccios Extra com Gabarito ..................................................................................13 I.8 Gabarito .....................................................................................................................16 Captulo II Ordenao .....................................................................................................19 II.1 Introduo .................................................................................................................19 II.2 SELEO DIRETA (SELECTION SORT) ................................................................22 II.3 BOLHA (BUBBLESORT) ..........................................................................................25 II.4 COQUETELEIRA (SHAKERSORT)..........................................................................28 II.5 INSERO DIRETA (INSERTION SORT) ...............................................................31 II.6 SHELLSORT .............................................................................................................33 II.7 MERGESORT ...........................................................................................................37 II.8 QUICKSORT .............................................................................................................40 II.9 HEAPSORT Seleo em rvore............................................................................44 II.10 COMPARAO ENTRE OS MTODOS DE ORDENAO INTERNA.................50 II.11 CONCLUSO .........................................................................................................52 II.12 EXERCCIOS ..........................................................................................................52 Captulo III - Pesquisa ........................................................................................................56 III.1 INTRODUO .........................................................................................................56 III.1.1 Estrutura em Pascal ..........................................................................................57 III.1.2 Estrutura em Java .............................................................................................58 III.2 PESQUISA SEQENCIAL EM TABELA DESORDENADA.....................................59 III.2.1 Pesquisa seqencial em Vetor..........................................................................59 III.2.2 Pesquisa seqencial em Lista Simplesmente Encadeada (LSE) ......................61 III.3 PESQUISA BINRIA ...............................................................................................63 III.3.1 Pesquisa Binria em Vetor (Pascal)..................................................................64 III.3.2 Procedimento Inicializa (Pascal) .......................................................................65 III.3.3 Procedimento Insere (Pascal) Insere ordenadamente ...................................65 III.3.4 Procedimento Retira (Pascal) Remove ordenadamente ................................65 III.3.5 Pesquisa Binria em Vetor (Java).....................................................................66 III.3.6 Procedimento Insere (Java) Insere ordenadamente ......................................66 III.3.7 Procedimento Retira Remove ordenadamente .............................................66 III.4 RVORES DE BUSCA ............................................................................................67 III.4.1 rvore Binria de Busca ABB ........................................................................67 III.4.2 rvore Binria de Busca sem Balanceamento ABB.......................................69 III.4.3 Balanceamento .................................................................................................73 III.5 RVORES AVL........................................................................................................75 III.6 TRANSFORMAO DE CHAVES (HASHING).......................................................84 III.6.1 Funo de transformao (Funo HASHING).................................................85 III.6.2 Tratamento de colises .....................................................................................86 III.7 NIL ...........................................................................................................................88 III.8 EXERCCIOS ...........................................................................................................89 1
Captulo IV ORGANIZAO DE ARQUIVOS .................................................................92 IV.1 INTRODUO ........................................................................................................92 IV.2 HISTRIA ................................................................................................................92 IV.3 HIERARQUIA DE MEMRIA ..................................................................................94 IV.4 O QUE UM BLOCO? ...........................................................................................96 IV.5 ARQUIVOS..............................................................................................................97 IV.5.1 Arquivo Seqencial ...........................................................................................97 IV.5.2 Arquivo Seqencial-Indexado ...........................................................................98 IV.6 RVORES B..........................................................................................................106 IV.7 RVORES B+ .......................................................................................................115 IV.8 TABELAS HASHING PARA ARMAZENAMENTO SECUNDRIO .......................116 IV.9 LISTA DE EXERCCIOS .......................................................................................116
CAPTULO I ORDENAO
I.1 Introduo
O que programar? Podemos dizer que programar estruturar dados e construir algoritmos. O que algoritmo? um procedimento computacional bem definido para resolver um problema computacional especificado, ou seja, recebe um valor ou um conjunto de valores como entrada e produz outro valor, ou conjunto de valores, como sada. Ento, podemos dizer que um algoritmo uma seqncia de passos computacionais que transformam uma entrada em sada. Ou seja, um algoritmo descreve um procedimento computacional para relacionar a entrada com a sada. Como saber se um algoritmo bom? Um algoritmo resolve um problema se, ao receber dados de entrada produzir, como sada, uma resposta correta, com tempo e memria suficientes para sua execuo. Mas, resolver o problema apenas no basta. Para que um algoritmo seja bem feito, importante que ele seja concebido de acordo com os seguintes passos. 1. Formalizao matemtica do problema: permite uma compreenso do que se pretende e facilita o compartilhamento do problema com outros. 2. Concepo do algoritmo: etapa criativa, quando so aplicadas as principais tcnicas de projeto de algoritmos. 3. Verificao de correo: deve-se garantir que o algoritmo est trabalhando corretamente, ou seja, est produzindo a sada correta. 4. Anlise de eficincia: se o algoritmo est correto, mas no eficiente, deve-se buscar outros mais eficientes. 5. Refinamento: introduzir alteraes no algoritmo para torn-lo correto e eficiente. Ento, ao se escrever um programa, alguns requisitos devem ser satisfeitos: Eficincia (tempo, execuo) Escrita (facilidade de entender) Reuso Para otimizar o funcionamento de um programa existem vrias possibilidades: Aumentar a velocidade do processamento da mquina, Trocar a forma de como o programa obtm a soluo (trocar de algoritmo) Ou melhorar a representao interna do dado que maneja. Os dois ltimos itens influenciam tambm na escrita e no reuso. O programador tem sob seu controle apenas os dois ltimos aspectos. Uma parte do ltimo item foi visto em estrutura de dados, onde se estudaram as formas de armazenamento dos dados. Em Pesquisa e Ordenao iremos ainda estudar formas de 3
armazenamento bem como algoritmos de pesquisa e ordenao para se trabalhar com estas formas, descobrindo diferenas entre vrios algoritmos e atravs destas estaremos aptos para saber qual escolher para um determinado problema. Quando se trabalha com dados geralmente se quer manipular tais dados: Inserir (armazenar) Acessar (ver) Remover (apagar) Etc.
Para isto necessrio escrever linhas de cdigo que faam tal trabalho. Por isso estruturas de dados e algoritmos esto intimamente ligados. Programar , basicamente, estruturar dados e construir algoritmos. De acordo com Wirth, programas so formulaes concretas de algoritmos abstratos, baseados em representaes e estruturas especficas de dados: PROGRAMA = ALGORITMO + ESTRUTURA DE DADOS
Nessa fase, necessrio fazer uma anlise do algoritmo. Segundo Knuth, h dois tipos de problemas que se deve observar: 1. Anlise de um algoritmo particular: Neste caso, deseja-se saber o custo de usar um determinado algoritmo para resolver um problema especfico (o nmero de vezes que cada parte do algoritmo executada, a quantidade de memria necessria, etc.). 2. Anlise de uma classe de algoritmos: Agora, deseja-se saber qual o algoritmo, dentre uma classe ou famlia, tem o menor custo possvel. Assim, possvel limitar a complexidade computacional de um algoritmo. No segundo tipo, ao determinar o menor custo de um algoritmo, tem -se a medida da dificuldade inerente ao resolver tal problema. Se um determinado algoritmo tem custo igual ao menor custo possvel, pode-se cham-lo de TIMO para a medida de custo considerada. Se h vrios algoritmos para resolver o mesmo problema, com esta medida possvel compar-los e escolher o melhor.
I.4.1 Como calcular o tempo que um algoritmo leva para ser executado? No calcularemos o tempo em segundos ou outra medida, pois isso pode variar muito ao mudar de mquina, mas sim calcularemos a quantidade de vezes que uma determinada instruo executada. Desta forma teremos um clculo independente de mquina. Para saber quanto tempo leva em uma determinada mquina, basta multiplicar o valor encontrado pelo tempo que a instruo demora a ser executada. Para medir a quantidade de trabalho que um algoritmo executa, necessrio escolher uma operao fundamental. Chamaremos aqui de CUSTO, a quantidade de instrues que so executadas por um algoritmo. Para chegar a este valor adotaremos os seguintes critrios: Para cada tarefa executada atribuo o valor de 1 unidade de tempo. Considerar os comandos de atribuio e comparao como operaes fundamentais.
Exemplo: Funo que verifica se A maior que B. int maior (int a, int b){ a) if (a>b) b) return a; else c) return b; } O tempo que este algoritmo levaria para ser executado seria 2 unidades de tempo, ou seja, o seu custo 2, pois se A > B o comando a e b sero executados (2 comandos). Se A <= B, a e c sero executados (2 comandos).
Exerccio: Calcule o custo para o algoritmo abaixo, supondo que o vetor vet tenha tamanho n int maior (int[] vet){ int i, max; int tam = vet.length; a) max = vet[0]; b) for (i=1; i<tam; i++) c) if (max < vet[i]) d) max = vet[i]; e) return max; } Pior caso (vetor ordenado): C(n) = 1 (a)+ 2*(n) (b) + (n-1) (c) + (n-1) (d) + 1(e) C(n) = 4n Melhor caso (vetor ordenado inversamente): C(n) = 1 (a) + 2*(n) (b) + (n-1) (c)+ 0 (d) +1(e) C(n) = 3n + 1
Neste algoritmo existem duas situaes: o melhor caso, ou seja, aquele em que temos um menor custo e o pior caso que nos leva para um custo maior. O pior caso ocorre quanto o vetor est ordenado crescentemente. Neste caso a varivel maior ser sempre menor que a[i] executando sempre o comando d. O melhor caso ocorre quando o vetor est ordenado decrescentemente. Neste caso a varivel maior ser sempre maior que a[i] nunca executando o comando d. O cabealho do FOR ser executado n vezes, mas como este cabealho executa um comando de atribuio (atribui um valor a i) e um comando de comparao (compara i com n), multiplica-se 2 por n dando o custo 2n.
O interior do FOR executado (n 1) vezes, visto que a ltima vez que o cabealho executado para finalizar o PARA no ocorrendo a execuo do interior. Sendo assim o comando c executado (n-1) vezes. O comando d ser executado (n-1) vezes no pior caso. Vejamos agora, um outro exemplo. Suponhamos que temos dois mtodos para resolver um mesmo problema, cuja entrada tem tamanho n, podemos ter: Mtodo 1: T1(n) = 2n + 5n operaes Mtodo 2: T2(n) = 500n + 4000 operaes Dependendo do valor de n, o mtodo 1 pode requerer mais ou menos operaes que mtodo 2.
2
I.5 Notao O
A notao O utilizada para expressar comparativamente o crescimento assinttico de duas funes. O crescimento assinttico representa a velocidade com que uma funo tende a infinito. Em termos de algoritmo, pode-se dizer que crescimento assinttico o crescimento da complexidade quando a quantidade de dados de entrada muito grande. No estudo de complexidade de algoritmos muitas vezes mais interessante saber como se comporta a funo medida q se aumenta o valor de n (nmero de registros), do ue que conhecer valores particulares para um n particular. Outras vezes muito complicado calcular o custo, ento uma aproximao feita. Por exemplo, mais importante saber que o nmero de operaes executadas num algoritmo dobra se dobrarmos o valor de n, do que saber que para n igual a 100 so executadas 100 operaes. Quando observamos entradas grandes o bastante para que somente a ordem de crescimento do tempo de execuo seja relevante, estudamos a eficincia assinttica do algoritmo. Ou seja, mais importante saber como o tempo de execuo aumenta, medida que a quantidade de dados de entrada aumenta sem limites. Normalmente, algoritmos assintoticamente mais eficientes, se comportaro de forma mel or com todas h as entradas, exceto, possivelmente, entradas muito pequenas. Diz-se que uma funo f(n) O(g(n)), se existirem constantes c e K tais que, para todo n>= K, tivermos f(n) <= c.g(n). Em outras palavras, para valores suficientemente grandes de n, a funo f (n) no ser maior do que g(n), a menos de um fator c. Isto nos permite ignorar as constantes e parcelas de ordem inferior de f(n).
2n
18 8 2 0
resultado
2n -5 x 2n
20 18 16 14 12 10 8 6 4 2 0 -2 0 -4 -6 -8 n
2 8 18
2n2 - 5 2n2
-4
-2
De maneira geral pode-se dizer que: O(1) < O(log2n)< O(n) < O(nlog n)< O(n ) < O(n ) < O(2 )
2 2 3 n
Deve-se ter cuidado ao utilizar a notao O, ela deve ser usada exclusivamente como uma aproximao da complexidade de um algoritmo, jamais deve ser usada para calcular a quantidade de operaes a ser efetuada. A importncia da complexidade pode ser observada pelo seguinte exemplo, que mostra 5 algoritmos A1 a A5 para resolver um mesmo problema, de complexidades diferentes. Supomos que uma operao leva 1 ms para ser efetuada. A tabela seguinte d o tempo necessrio por cada um dos algoritmos. (Sempre suporemos logaritmos na base 2.)
A5 T5(n) = 2 1m 4s 46 dias
137 n
sculos
Podemos muitas vezes melhorar o tempo de execuo de um programa (que implementa um algoritmo dado) fazendo otimizaes locais (e.g. usar x+x ao invs de 2x, em mquinas em que a multiplicao mais demorada que a adio). Entretanto, melhorias substanciais so muitas vezes obtidas se usarmos um algoritmo diferente, com outra complexidade de tempo, e.g. obter um algoritmo de O(nlog2n) ao 2 invs de O(n ). Caractersticas das principais classes de funes de complexidade: F(n) = O(1): Complexidade constante. O uso do algoritmo independe do tamanho da entrada, ou seja, todas as instrues so executadas um nmero fixo de vezes, independente do tamanho da entrada. F(n) = O(log2n): Complexidade logartmica. Tipicamente para algoritmos que resolvem um problema transformando-o em problemas menores. Se a entrada dobrar de tamanho, o tempo de execuo aumenta de uma 2 unidade, ou seja, para o tempo de execuo dobrar, a entrada deve ser n . F(n) = O(n): complexidade linear. Em geral um pequeno trabalho realizado sobre cada elemento de entrada. Esta a melhor situao possvel para algoritmos que tm que processar os n elementos da entrada ou produzir n elementos de sada. Cada vez que n dobrar de tamanho, o tempo de execuo dobra. F(n) = O(nlog2n): Ocorre para algoritmos que resolvem o problema quebrando-o em problemas menores, resolvendo cada um deles independente e depois juntando as solues. Cada vez que n dobrar de tamanho, o tempo de execuo ser maior que o dobro. F(n) = O(n ): Complexidade quadrtica. Ocorre quando os itens so processados aos pares, muitas vezes com um lao dentre de outro. So 9
2
muito teis para resolver problemas relativamente pequenos. Cada vez que n dobrar de tamanho, o tempo de execuo ser multiplicado por 4. F(n) = O(n ): Complexidade cbica. So teis apenas para problemas pequenos. Cada vez que n dobrar de tamanho, o tempo de execuo ser multiplicado por 8. F(n) = O(2 ) : Complexidade exponencial. Geralmente no so teis, pois ocorrem na soluo de problemas quando se usa a fora bruta. Cada vez que n dobrar de tamanho, o tempo de execuo ser elevado ao quadrado. Pode-se perceber que, na prtica, algoritmos polinomiais (O(n), O(n ), O(n ), etc.) so n n mais teis do que os exponenciais (O(2 ), O(3 ), etc.) porque quando o tamanho do problema a ser resolvido cresce, o tempo de execuo no segundo tipo cresce muito mais rpido. Os algoritmos exponenciais, geralmente, so simples variaes de pesquisa exaustiva, enquanto os polinomiais so construdos aps um entendimento mais amplo da estrutura do problema. Portanto, se, para um problema no existir um algoritmo polinomial para resolv-lo, ele dito INTRATVEL. Caso contrrio, ele dito BEM RESOLVIDO. Mas, existem alguns algoritmos exponenciais bem sucedidos, como por exemplo, o SIMPLEX, que vocs vero na disciplina Pesquisa Operacional, e ainda outros mal sucedidos, como o caso do Caixeiro Viajante, ao acrescentar muitos locais de visita.
2 3 n 3
I.6 Exerccios
1) Coloque em ordem crescente as seguintes funes pela dominao assinttica. Dica: 2 3 4, ... Faa uma tabela e teste vrios valores de n:10, 10 , 10 , 10 .
A(n) = 500
C (n ) =
D(n) = log 2 n
n 1 + 2 n2 F (n) = log n +
5 n
2) Idem ao anterior:
A(n) = n
B( n) = n log n
1 F (n ) = 3
n
C (n) = log n
3 G ( n) = 2
n
E (n) = log2 n
D( n) = n log 2 n n H (n ) = log n
3) Suponha que voc tem quatro algoritmos distintos para resolver o mesmo problema. As
onde n o tamanho da entrada. Que algoritmos voc escolheria para entradas de 2, 10, 25 e 100, respectivamente? 10
b) Matriz mat nXn void iniciaMatriz (int[][] mat){ int l, c; for (l=0; l<mat.length; l++) for (c=0; c<mat[l].length; c++) mat[l][c] = 0; }
c) int calculo (int n){ int i, j, result=0; for (i=2; i<=n; i++) for (j=i; j<=n; j++) result++; return result; }
d) int calculo (int n){ int i, j, result=0; for (i=1; i<=n; i++) for (j=i+1; j<=2*n+i; j++) result+=j; return result; }
e) Calcule o custo do FOR para o algoritmo abaixo que calcula o n -simo termo da srie de fibonaci (0,1,1,2,3,5,8,13,21...). int fibonacci (int n){ int f1, f2, f3=0, i; if (n ==1) return 0; if (n == 2) return 1; f1 = 0; f2 = 1; for (i=3; i<=n; i++){ f3 = f1 + f2; f1 = f2; f2 = f3; } return f3; }
11
g) vet de tamanho n boolean existe (double[] vet, double x){ int i; i=0; while (i<vet.length && x != vet[i]) i++; return (i<vet.length); }
h) double integral (double a, double b, int n){ double h, soma, x, y; int c, i; h = (b-a)/n; soma = Math.sin(a)+Math.sin(b); for (i=1; i<n; i++){ x = a + i * h; y = Math.sin(x); c = 2 * (i%2 + 1); soma += c*y; } return (soma*h)/3; }
i) int calculo (int n){ int i, j, result=0; for (i=1; i<=n; i++) for (j=(i+1); j<=(n+i); j++) result += j; return result; }
12
j) int calculo (int n){ int i, j, result=0; for (i=1; i<=n; i++) for (j=(i+1); j<=n; j++) result += j; return result; } k) int[][] multiplicao (int[][] m1, int[][] m2){ int[][] mult; int i, j, k, m = m2.length, n=m1.length, p=m2[0].length; if (m1[0].length != m) return null; mult = new int[n][p]; for (i=0; i<n; i++) for (j=0; j<p; j++) for (k=0; k<m; k++) mult[i][j]+=m1[i][k]*m2[k][j]; return mult; } l) int posicao (double[] vet, double x){ int i=-1; do{ i++; }while (i<vet.length && x!=vet[i]); if (i==vet.length) return -1; else return i; }
13
b) void vetMaior(int[] vet, int[][] mat){ int i, j; for (i=0; i < mat.length; i++){ vet[i] = mat[i][0]; for (j=1; j<mat[i].length; j++){ if (mat[i][j]>vet[i]) vet[i] = mat[i][j]; } } }
c) boolean procura (int[][] vet, int num){ int i, j; i=0; while (i<vet.length){ j=i; while (j<vet.length){ if (vet[i][j]==num) return true; j++; } i++; } return false; }
d) int somaSimetrica (int[][] mat){ int soma=0, i, j; for (i=0; i<mat.length; i++){ for (j=0; j<i; j++) soma += mat[i][j]*2; soma += mat[i][i]; } return soma; }
e) long calculo (int[][] mat){ int i, j; long temp=0; for (i=0; i<mat.length-1; i++) for(j=i+1; j<mat[i].length; j++) temp += mat[i][j]; return temp; }
14
f) int soma3m (int[] vet){ int i=0, temp=0; while (i<vet.length && vet[i]<=0) i++; while (i<vet.length){ if (vet[i]%3 == 0) temp = temp + vet[i]; i++; } return temp; }
g) void triangPascal (int[][] mat){ int i, j; for (i=1; i<mat.length; i++){ mat[i][0] = 1; for (j=1; j<=i; j++) mat[i][j] = mat[i-1][j]+ mat[i-1][j-1]; } }
h) static int linhaZero (int[][] mat){ int i, j, zero=0; for (i=0; i<mat.length;i++){ zero = 0; for (j=0; i<mat[i].length; j++){ if (mat[i][j]==0) zero++; } if (zero==mat[i].length) return i; } return -1; }
15
I.8 Gabarito
a) boolean triangSup (int[][] mat){ int i=1, j; while (i<mat.length){ j=0; while (j<i){ if (mat[i][j]!=0) return false; j++; } i++; } return true; } C(n) = Melhor Caso Pior Caso
1 1 1 1 1 1
0 0 0
1 n n 1 n 2 + .n 2 2 n2 n 2 0 n2 n 2
n 1
1
3n 2 + 5n 2 2
b) void vetMaior(int[] vet, int[][] mat){ int i, j; for (i=0; i < mat.length; i++){ vet[i] = mat[i][0]; for (j=1; j<mat[i].length; j++){ if (mat[i][j]>vet[i]) vet[i] = mat[i][j]; } } } C(n) =
Melhor Caso
Pior Caso
2( n + 1) n 2n 2 n2 n 0
2( n + 1) n 2n 2 n2 n n2 n
3n 2 + 2n + 2
4n2 + n + 2
16
c) boolean procura (int[][] vet, int num){ int i, j; i=0; while (i<vet.length){ j=i; while (j<vet.length){ if (vet[i][j]==num) return true; j++; } i++; } return false; } C(n) =
Melhor Caso
Pior Caso
1 1 1 1 1 1
0 0 0 6
1 n +1 n n 2 + 3n 2 2 n +n 2 0 n2 + n 2
n
1
3n 2 + 11n + 6 2
d) int somaSimetrica (int[][] mat){ int soma=0, i, j; for (i=0; i<mat.length; i++){ for (j=0; j<i; j++) soma += mat[i][j]*2; soma += mat[i][i]; } return soma; } C(n) = e) long calculo (int[][] mat){ int i, j; long temp=0; for (i=0; i<mat.length-1; i++) for(j=i+1; j<mat[i].length;j++) temp += mat[i][j]; return temp; } C(n) =
1 2( n + 1) n2 + n n2 n 2 n2 + n 2 1
2 n 2 + 3n + 4
1 2n n2 + n 2 n2 n 2 1
3n 2 + 5n 2
17
f) Melhor Caso: Vetor com todos os valores negativos ou zero. Pior Caso: vet[0] > 0 e todos os valores mltiplos de 3. int soma3m (int[] vet){ int i=0, temp=0; while (i<vet.length && vet[i]<=0) i++; while (i<vet.length){ if (vet[i]%3 == 0) temp = temp + vet[i]; i++; } return temp; } C(n) = g) void triangPascal (int[][] mat){ int i, j; for (i=1; i<mat.length; i++){ mat[i][0] = 1; for (j=1; j<=i; j++){ mat[i][j]=mat[i-1][j]+mat[i-1][j-1]; } } } C(n) = Melhor Pior
2 2n + 1 n 1 0 0 0 1
3n + 5
2 2 0 n +1 n n n 1
4n + 6
2n n 1 n2 + n 2 n2 n 2
3n 2 + 7n 6 2
h) Melhor Caso: 1 linha zerada Pior Caso: todas as colunas zeradas, exceto a ltima static int linhaZero (int[][] mat){ int i, j, zero=0; for (i=0; i<mat.length;i++){ zero = 0; for (j=0; i<mat[i].length; j++){ if (mat[i][j]==0) zero++; } if (zero==mat[i].length) return i; } return -1; } C(n) = Melhor Pior
1 2 1 2( n + 1) n n 1 1
0 4n + 8
1 2( n + 1) n 2 n(n + 1) n2 n (n 1)
n 0
1
4 n 2 + 5n + 4
18
CAPTULO II ORDENAO
II.1 Introduo
A ordenao uma operao fundamental em Cincia da Computao, pois muitos programas a utilizam como uma etapa intermediria. Por isso, foram desenvolvidos muitos algoritmos de ordenao. K O que ordenar? Rearranjar um conjunto de objetos em uma ordem crescente ou decrescente. K Objetivo Facilitar a recuperao posterior, dos dados armazenados. Pesquisar e recuperar dados. K Como os algoritmos trabalham? Sobre os registros de um arquivo, atravs de uma chave de pesquisa que um campo especial do registro que controla a ordenao. O registro pode conter outros campos que independem da chave. TIPO ITEM = REGISTRO CHAVE: TPCHAVE; {OUTROS CAMPOS} FIM; Em JAVA, os algoritmos devem trabalhar sobre uma classe, no mais sobre um tipo registro. class Item { private tipoChave chave; // outros atributos // construtor(es) e mtodos para manipular os atributos, dentre eles: public tipoChave getChave ( ){ return chave; } } O tipo da CHAVE pode ser qualquer um que se possa ordenar de forma bem definida. A ordem mais comum numrica ou alfabtica. Existem vrios algoritmos de ordenao. A escolha do melhor algoritmo para uma aplicao depende do nmero de itens a ser ordenado, de quantos itens j esto ordenados de algum modo, de possveis restries aos valores dos itens, do dispositivo de armazenamento utilizado, etc.
19
K Ambiente de Classificao O meio de armazenamento afeta o processo de classificao Ordenao interna Ocorre quando o arquivo a ser ordenado cabe todo na memria principal. O nmero de registros pequeno o suficiente para caber em um array, definido por uma linguagem de programao. Neste tipo de ordenao, qualquer registro pode ser imediatamente acessado. Ordenao externa Ocorre quando o arquivo no cabe na memria principal e deve ser armazenado em fita ou disco (memria externa tempo maior). Neste tipo de ordenao, os registros so acessados seqencialmente ou em grandes blocos.
K Medidas de complexidade relevantes Para se escolher um algoritmo de ordenao, necessrio saber o tempo gasto para ordenar um arquivo. Para um algoritmo de ordenao interna, necessrio saber: Comparaes de chaves - C (n) Movimentaes de itens - M (n) Onde n o nmero de itens do arquivo. Tambm necessrio saber a quantidade de memria auxiliar utilizada pelo algoritmo, pois necessrio fazer uso de maneira econmica da memria. K Apresentao do resultado J Contiguidade fsica 25 37 1 2 12 1 15 2
15 3 20 3
12 4 25 4
20 5 37 5
15 3 5 3
12 4 1 4
20 5 2 5
20
J Encadeamento
25 1
37 2
NIL
15 3
12 4
20 5
Primeiro = 4 Os mtodos preferidos so aqueles que utilizam vetor como estrutura de dados e fazem permutao de itens no prprio vetor. Os mtodos que utilizam listas encadeadas so utilizados em situaes muito especiais porque utilizam n palavras extras para armazenar os apontadores. Os mtodos que precisam de uma quantidade extra de memria para armazenar uma outra cpia dos itens que sero ordenados so menos importantes.
Algoritmos de Ordenao Interna Mtodos simples O (n ) comparaes arquivos pequenos. Produzem programas pequenos e fceis de entender por isso, em muitos casos, melhor usar mtodos mais simples do que mais sofisticados. Mtodos eficientes O (n logn) comparaes - arquivos grandes. As comparaes usadas so mais complexas nos detalhes.
2
Ao implementar um algoritmo de ordenao nterna (em Pascal), sero utilizados os i seguintes tipos de dados e variveis: TYPE INDICE = 1..N; VETOR = ARRAY [INDICE] OF ITEM; VAR A : VETOR;
Em Java ser utilizada a seguinte classe: class Dados{ private Item[] vetor; //referncia a um vetor de ite ns private int nElem; //nmero de itens de dados //construtor(es) e mtodos desta classe }
21
Um mtodo de ordenao dito ser estvel quando a ordens dos itens com chaves iguais mantm-se inalterada pelo processo de ordenao. Por exemplo, uma lista, em ordem crescente de matrcula dos funcionrios de uma empresa, ordenada pelo campo nome. Se o mtodo de ordenao utilizado for estvel, ele produzir uma lista onde funcionrios com o mesmo nome aparecero ordenados por matrcula.
7 Luiz Dantas 4
3 Maria Freitas 5
Alguns mtodos mais eficientes no so estveis. Mas, para um mtodo no-estvel, a estabilidade pode ser forada, se ela for importante.
179 179
254 254
450 i 351
520 520 i
652 652
861 861
22
179
254
285
310
351
423
450
520
861
Ordenado!!!
Baseado no exemplo anterior e no princpio de funcionamento do mtodo, ns vamos desenvolver o algoritmo de ordenao por seleo em Java, supondo que este mtodo est na classe Dados e em Pascal: PASCAL: PROCEDURE SELECAO ( VAR A: VETOR); VAR I, J, MIN : INTEGER; AUX: ITEM; BEGIN FOR I := 1 AT N-1 DO BEGIN MIN := I; FOR J:= I+1 TO N DO IF (A[J].CHAVE < A[MIN].CHAVE) THEN MIN := J; AUX := A[MIN]; A[MIN] := A[I]; A[I] := I; END; END;
JAVA: public void seleoDireta (){ int i, j, minimo; Item temp; for (i=0; i< this.nElem-1;i++){ minimo = i; for (j=i+1; j< this.nElem; j++) if (this.vetor[j].getChave ()< this.vetor[minimo].getChave()) minimo = j; temp = this.vetor[minimo]; this.vetor[minimo] = this.vetor[i]; this.vetor[i] = temp; } }
23
Aps o desenvolvimento do algoritmo, vamos calcular seu custo: COMPARAES C(n) = MOVIMENTAES M(n) = 3(n 1) Observem que o nmero de movimentaes linear no tamanho da entrada
n2 n 2 2
CONSIDERAES SOBRE O MTODO: Nmero de movimentaes linear Bom para arquivos com registros grandes Bom para arquivos com at 1000 registros se a chave tem tamanho igual a 1 palavra Se o arquivo j est ordenado ou quase, isso no ajuda em nada. C(n) continua quadrtico Algoritmo no estvel. Exemplo da no estabilidade do algoritmo: Seja o vetor abaixo, onde o primeiro campo um cdigo e o segundo um nome. Supondo que o vetor esteja ordenado por cdigo e deseja-se reorden-lo por nome. Se o algoritmo fosse estvel, ao aparecer nomes iguais, viria primeiro aquele com menor cdigo. 1 KTIA 2 CARLOS 3 LUCAS 4 JOS 5 LUCAS 6 JLIA
Ao simular o algoritmo, notamos que o vetor final, ordenado por nome ficaria: 2 CARLOS 4 JOS 6 JLIA 1 KTIA 5 LUCAS 3 LUCAS
24
25
254 254 j 254 254 254 254 254 j 254 254 j 179 Lsup j
179 179 179 310 310 310 310 310 310 310
450 450 450 450 351 j 351 351 351 351 351
423 j 423 Lsup 423 450 Lsup 423 450 423 450
423 j 423 Lsup 423 Lsup 423 Lsup 423 Lsup 450 Lsup 450
520 652 Lsup 520 652 520 520 520 520 520 520 520 520 652 652 652 652 652 652 652 652
861 861 861 861 861 861 861 861 861 861
Ordenado!!!
Baseado no exemplo anterior e no princpio de funcionamento do mtodo, ns vamos desenvolver o algoritmo Bubblesort em Pascal e em Java: PASCAL:
PROCEDURE BOLHA (VAR A: VETOR; N: INTEGER); VAR LSUP, I, J: INTEGER; AUX: ITEM; BEGIN LSUP := N; REPEAT J := 0; FOR I := 1 AT LSUP-1 DO IF (A[I].CHAVE > A[I+1].CHAVE) THEN BEGIN AUX := A[I]; A[I] := A[I+1]; A[I+1] := AUX; J := I; END; LSUP := J; UNTIL (LSUP <= 1);
END;
26
JAVA: public void bubblesort (){ int LSup, i, j; Item temp; LSup = this.nElem-1; do{ j = 0; for (i = 0; i < LSup; i++) if (this.vetor[i].getChave() > this.vetor[i+1].getChave()){ temp = this.vetor[i]; this.vetor[i] = this.vetor[i+1]; this.vetor[i+1] = temp; j = i; } LSup = j; }while (LSup >= 1); } Aps o desenvolvimento do algoritmo, vamos calcular seu custo: COMPARAES MELHOR CASO: Vetor j est ordenado C(n) = n 1 PIOR CASO: Vetor ordenado em ordem contrria C(n) =
n2 n 2 2
MOVIMENTAES
MELHOR CASO: Vetor j est ordenado. M(n) = 0 PIOR CASO: Vetor ordenado em ordem contrria M(n) =
3n 2 3n 2 2
CONSIDERAES SOBRE O MTODO: Parece o algoritmo de Seleo Faz muitas trocas, o que o torna o menos eficiente dos mtodos Simples ou Diretos um mtodo estvel Se o arquivo estiver quase ordenado ele costuma ser eficiente, mas deve-se tomar cuidado com o caso em que o arquivo est ordenado, com exceo do menor elemento que est na ltima posio. Neste caso, o algoritmo far o mesmo nmero de comparaes do pior caso. um mtodo lento, pois s compara posies adjacentes. Cada passo aproveita muito pouco do passo anterior Comparaes redundantes, pois o algoritmo linear e obedece a uma seqncia fixa de comparaes. 27
28
179 179 179 179 179 179 179 179 179 179
450 450 450 450 254 254 254 254 254 254
254 esq 254 esq 254 esq 254 esq 450 esq/j 285 j 285 285 285 285
310 310 310 285 285 450 esq 310 esq 310 esq 310 esq 310
285 285 285 310 j 310 310 450 j 351 351 351
351 351 351 351 351 351 351 450 j 423 dir 423 dir
520 520 423 423 423 423 423 423 450 j 450 j
423 423 dir 520 dir/j 520 dir 520 dir 520 dir 520 dir 520 dir 520 520 esq
652 j 652 j 652 652 652 652 652 652 652 652
861 dir 861 861 861 861 861 861 861 861 861
Ordenado!!!
Baseado no exemplo anterior e no princpio de funcionamento do mtodo, ns vamos desenvolver o algoritmo Shakersort em Pascal e em Java: PASCAL:
PROCEDURE SHAKERSORT (VAR A: VETOR; N:INTEGER); VAR ESQ, DIR, I, K: INTEGER; AUX: ITEM; BEGIN ESQ := 2; DIR := N; K := N; REPEAT FOR I := DIR DOWNTO ESQ DO {leva as menores chaves para o incio} IF (A[I1].CHAVE > A[I].CHAVE) THEN BEGIN AUX := A[I]; A[I] := A[I1]; A[I1] := AUX; K := I; END; ESQ := K + 1; FOR I := ESQ TO DIR DO {leva as maiores chaves para o final} IF (A[I1].CHAVE > A[I].CHAVE) THEN BEGIN AUX := A[I]; A[I] := A[I1]; A[I1] := AUX; K := I; END; DIR := K 1; UNTIL (ESQ > DIR); END;
29
JAVA: public void shakersort (){ int esq, dir, i, j; Item temp; esq = 1; dir = this.nElem 1; j = dir; do{ //leva as menores chaves para o incio for (i = dir ; i >= esq; i-- ) if (this.vetor[i-1].getChave() > this.vetor[i].getChave()){ temp = this.vetor[i]; this.vetor[i] = this.vetor[i1]; this.vetor[i1] = temp; j = i; } esq = j+1; //leva as maiores chaves para o final for (i = esq ; i <= dir; i++) if (this.vetor[i1].getChave() > this.vetor[i].getChave()){ temp = this.vetor[i]; this.vetor[i] = this.vetor[i1]; this.vetor[i1] = temp; j = i; } dir = j1; }while (esq <= dir); } Aps o desenvolvimento do algoritmo, vamos calcular seu custo:
COMPARAES
MELHOR CASO: Vetor j est ordenado C(n) = n 1 PIOR CASO: Vetor ordenado em ordem contrria C(n) =
n2 n 2 2
MOVIMENTAES
MELHOR CASO: Vetor j est ordenado. M(n) = 0 PIOR CASO: Vetor ordenado em ordem contrria M(n) =
3n 2 3n 2 2
CONSIDERAES SOBRE O MTODO: Parece o algoritmo BUBBLESORT Faz muitas trocas, o que o torna um dos menos eficientes dentre os mtodos Simples ou Diretos um mtodo estvel 30
31
179 179 179 179 179 179 179 179 179 179 179
254 254 254 254 254 254 254 254 254 254 254
285 285 285 285 285 285 285 285 285 285 285
310 310 310 310 310 j 310 310 310 310 310 310
450 450 450 450 j 450 351 351 351 351 j 351 351
520 j 520 520 j 520 450 450 450 450 j 450 423 423
652 i 652 j 652 520 520 520 520 j 520 450 450 450
351 351 i 652 i 652 i 652 i 652 j 652 520 520 520 520
423 423 423 423 423 423 i 652 i 652 i 652 i 652 j 652
861 861 861 861 861 861 861 861 861 861 i 861
423 temp
861 temp
Ordenado!!!
Baseado no exemplo anterior e no princpio de funcionamento do mtodo, ns vamos desenvolver o algoritmo de Insero Direta em Pascal e em Java: PASCAL: PROCEDURE Insercao ( VAR A: VETOR); VAR I, J : INTEGER; Aux: item; BEGIN FOR I:= 2 AT N DO BEGIN Aux := A [I] ; J := I1; WHILE (J > 0) AND (A[J]. Chave > aux.chave) DO BEGIN A[J+1] := A[J]; J := J 1; END; A [J+1] := aux; END; END;
32
JAVA: public void inseroDireta(){ int i, j; Item temp; for (i=1; i < this.nElem; i++){ temp = this.vetor[i]; j = i1; while ((j >= 0) && (this.vetor[j].getChave() > temp.getChave())){ this.vetor [j+1] = this.vetor[j]; j--; } this.vetor [j+1] = temp; } } Aps o desenvolvimento do algoritmo, vamos calcular seu custo: COMPARAES MELHOR CASO: Vetor j est ordenado C(n) = n 1 PIOR CASO: Vetor ordenado em ordem contrria C(n) =
n2 n 2
MOVIMENTAES
MELHOR CASO: Vetor j est ordenado. M(n) = 2 ( n 1) PIOR CASO: Vetor ordenado em ordem contrria n 2 + 3n 4 M(n) = 2
CONSIDERAES SOBRE O MTODO: Bom para vetores quase ordenados Bom quando se deseja adicionar poucos itens, de forma ordenada, a um arquivo j ordenado, pois a ordem, neste caso, linear. Mtodo estvel.
II.6 SHELLSORT
Este mtodo uma extenso do algoritmo de ordenao por insero. Mtodo de insero ?Se o menor item est na posio mais direita, ento o nmero de comparaes e movimentaes para encontrar seu ponto de insero (n 1). Mtodo Shell ?Permite troca de registros de posies distantes (h posies). Eles so comparados e trocados. A seqncia ordenada para um certo h, dizemos que esta seqncia est h-ordenada. Quando h=1, o algoritmo funciona como o algoritmo de insero. 33
h=2
h=1
34
Ordenado!!!
J houve vrias experincias de seqncias de h Knuth mostrou, experimentalmente, . que existe uma seqncia que melhora a eficincia do tempo de execuo em cerca de 20%. Esta seqncia : 1, 4, 13, 40, 121, ... ou seja, h(s) = 3h(s-1) + 1, para s > 1 h(s) = 1, para s = 1 Baseado no exemplo anterior e no princpio de funcionamento do mtodo, ns vamos desenvolver o algoritmo Shellsort em Pascal e em Java: PASCAL: PROCEDURE Shellsort ( VAR A: VETOR; N : INTEGER); VAR I, J, H : INTEGER; Aux: item; BEGIN H := 1; REPEAT H := 3*H+1; UNTIL (H > N); REPEAT H := H div 3; FOR I := H+1 TO N DO BEGIN Aux := A[I] ; J := I-H; WHILE (j > 1) AND (A[J].Chave > aux.chave) DO BEGIN A[J+H] := A[J]; J := JH; END; A [J] := aux; END; UNTIL (h = 1); END;
35
JAVA: public void shellsort (){ int i, j, h; Item temp; h = 1; do{ h = 3*h+1; }while (h < this.nElem); do{ h = h/3; for (i=h; i < this.nElem; i++){ temp = this.vetor[i]; j = i; while (this.vetor[jh].getChave() > temp.getChave()){ this.vetor[j] = this.vetor[jh]; j = h; if (j < h) break; } this.vetor [j] = temp; } }while (h != 1); }
ANLISE: Ningum ainda foi capaz de analisar este algoritmo. Portanto, ningum sabe porque ele eficiente. Uma pergunta comum : Como escolher os incrementos? No sabemos, mas cada incremento no deve ser mltiplo do anterior. Quanto complexidade, conjeturas apontam para: 1) C(n) = O(n ) 2 2) C(n) = O(n (ln n) ) CONSIDERAES tima opo para arquivos com ?.000 registros 5 Implementao simples Quantidade de cdigo pequena O tempo de execuo sensvel ordem inicial do arquivo Mtodo no estvel
1,25
36
II.7 MERGESORT
Este um mtodo de ordenao que divide o vetor ao meio e ordena, recursivamente, as duas metades do vetor. Aps isso, une cada metade, produzindo um outro vetor ordenado. Ele usa o mtodo de diviso e conquista. Diviso ] Divide o problema em duas ou mais partes, criando subproblemas menores. Conquista ] Os problemas so resolvidos recursivamente. Caso os subproblemas sejam pequenos, so resolvidos de maneira direta. Combinao ] Toma cada uma das partes e junta-as para resolver o problema original.
FUNCIONAMENTO: Dividir o vetor ao meio Ordenar a primeira metade recursivamente. Ordenar a segunda parte recursivamente. Intercalar as duas metades.
37
520 520 520 520 179 esq 179 esq 179 esq meio 179 652 meio 652 dir 652 652 351 351 351 esq/dir 179 652 652 423 esq 423 861 dir 861 861 861 423 861 652 351 meio 351 dir 351 423 861 423 423 861 dir 861
254
285
310
450
520
179
254
285
310
450
520
179
254 179
285 254
310 285
450 310
520 351
179 423
351 450
423 520
652 652
Ordenado!!!
Baseado no exemplo anterior e no princpio de funcionamento do mtodo, ns vamos desenvolver o algoritmo de Insero Direta em Pascal e em Java: PASCAL: PROCEDURE MERGESORT(INICIO : INTEGER, INT FIM :INTEGER); VAR MEIO : INTEGER; BEGIN IF (INICIO < FIM) THEN BEGIN MEIO=(INICIO + FIM) DIV 2; MERGESORT (INICIO, MEIO); MERGESORT (MEIO+1, FIM); MERGE (INICIO, MEIO, FIM); END; END; PROCEDURE MERGE (INICIO : INTEGER, MEIO : INTEGER, FIM : INTEGER); VAR H, I, J, MEIO : INTEGER; BEGIN 38
H=INICIO; I=INICIO; J=MEIO + 1; WHILE (H<=MEIO) E (J<=FIM) DO BEGIN IF (VET[H].CHAVE <= VET[J].CHAVE) THEN BEGIN TEMP[I] = VET[H]; H = H + 1; END ELSE BEGIN TEMP[I] = VET[J]; J= J + 1; END; I= I + 1; END; IF H > MEIO THEN FOR K=J TO FIM DO BEGIN TEMP[I] = VET[K]; I= I + 1; END; ELSE FOR K=H TO MEIO DO TEMP[I] = VET[K]; I= I + 1; END; FOR K=INICIO TO FIM DO //COPIA O CONJUNTO ORDENADO DE VOLTA VET[K] = TEMP[K]; END;
JAVA:
public void mergeSort(){ mergeSort (0, this.tamanho-1); } private void mergeSort (int esq, int dir){ int meio; if (esq == dir) return; else{ meio = (esq+dir)/2; mergeSort (esq, meio); mergeSort (meio+1, dir); merge (esq, meio+1, dir); } }
39
private void merge (int esq, int dir, int limSup){ int limInf = esq; int meio = dir -1; int n = limSup - limInf + 1; VetorInteiro temp = new VetorInteiro(n); while (esq <= meio && dir <= limSup) if (this.vetor[esq] < this.vetor[dir]){ temp.inserir(this.vetor[esq]); esq++; } else { temp.inserir(this.vetor[dir]); dir++; } while (esq <= meio){ temp.inserir(this.vetor[esq]); esq++; } while (dir <= limSup){ temp.inserir(this.vetor[dir]); dir++; } for (int j=0; j<n; j++) this.vetor[limInf+j] = temp.getElem(j); }
Este algoritmo funciona sempre igual, independente da disposio das entradas, (ordenada, aleatria ou inversamente ordenada. Assim, no existe pior caso nem melhor caso. Seu custo da ordem:
C (n) = n log n
CONSIDERAES um algoritmo fcil de implementar. Requer o dobro de memria, ou seja, precisa de um vetor com as mesmas dimenses do que se quer ordenar.
II.8 QUICKSORT
Princpio de funcionamento: a) escolher arbitrariamente um item do vetor como piv b) percorrer o vetor a partir de seu incio, at encontrar um item com chave maior ou igual chave do piv ] ndice i c) percorrer o vetor a partir do final, at encontrar um item com chave menor ou igual chave do piv ] ndice j d) trocar os itens v[i] e v[j] e) continuar o percurso-e-troca at que os dois ndices se cruzem 40
Obs: quando i e j se cruzam, temos dois grupos: v[l],..., v[j] <= piv v[j+l],..., v[n] >= piv
285 piv
254 310 i 310 310 i 310 310 i 310 310 i 310 310 i/j 450 i 450 450 i 450 450 i 423 423 i 351 j 351 j 520 i 520 520 i 351 351 351 i/j 351 j 423 i 310 piv 652 i 423 423 423 i/j 423 j 450 i 423 piv 351 351 i/j 351 j 520 i 450 piv 423 j 652 i 861 j 861 520 piv 652 piv
41
310 j
351 i 423 450 520 652 i/j 652 j 861 j 861 i 861 652 piv
179
285
254
310
351
423
450
520
652
Ordenado!!!
PASCAL: PROCEDURE QUICKSORT (VAR V : VETOR; N : INTEGER); PROCEDURE ORDENA (ESQ, DIR : INTEGER; VAR V: VETOR); VAR PIVO : TP_CHAVE; AUX : ITEM; I, J : INTEGER; BEGIN I := ESQ; J := DIR; PIVO := V{(I+J) DIV 2]. CHAVE; REPEAT WHILE (V[I].CHAVE < PIVO) DO I := I+1; WHILE (V[J].CHAVE > PIVO) DO J := J1; IF (I <= J) THEN BEGIN AUX := V[I]; V[I] := V[J]; V[J] := AUX; I := I+1; J := J1; END; UNTIL (I > J); IF (ESQ < J) THEN ORDENA (ESQ, J, V); IF (DIR > I) THEN ORDENA (I, DIR, V); END; {ORDENA} BEGIN ORDENA (1, N, V); END; {QUICKSORT};
42
JAVA: public void quicksort (){ ordena (0, this.nElem1);} private void ordena (int esq, int dir){ int pivo, i = esq, j = dir; Item temp; pivo = this.vetor[(i+j)/2].getChave(); do { while (this.vetor[i].getChave() < pivo) i++; while (this.vetor[j].getChave() > pivo) j--; if (i <= j) { temp = this.vetor[i]; this.vetor[i] = this.vetor[j]; this.vetor[j] = temp; i++; j; } } while (i <= j); if (esq < j) ordena (esq, j); if (dir > i) ordena (i, dir); } PIOR CASO: Escolha como piv de um dos extremos do arquivo j ordenado. H n chamadas recursivas, onde ser eliminado um elemento por vez. Logo, necessita de uma pilha auxiliar para as chamadas recursivas de tamanho n e, o nmero de comparaes : 2 C(n) = n / 2 MELHOR CASO: Dividir o arquivo ao meio. C(n) = 2C(n/2) + n Onde C(n/2) o custo de ordenar cada metade e n o custo de examinar cada item. Logo, C(n) ?,4 n logn 1 Sendo, em mdia, o tempo de execuo O(n logn).
CONSIDERAES: No bom para arquivos j ordenados quando a escolha do piv no boa. um algoritmo muito eficiente Precisa, em mdia n logn operaes para ordenar n itens Necessita de uma pequena pilha como memria auxiliar Mtodo no estvel 2 A verso recursiva tem como pior caso O(n ) operaes Implementao delicada e difcil. Um pequeno engano pode levar a efeitos inesperados 43
Como evitar o pior caso? Escolha 3 itens quaisquer do arquivo e use a mediana dos 3 como item divisor na partio.
OBS.: Esta relao baseada em um vetor cujo primeiro elemento posio 1, o que acontece em linguagens como Pascal e Delphi.
encontra-se na
Mas, em linguagens como Java, C e C++, onde a primeira posio do vetor a posio 0, a relao : O sucessor esquerda do elemento de ndice i o elemento de ndice 2i+1 e o sucessor direita o elemento de ndice 2i + 2, sendo que a chave de cada n maior ou igual s chaves de seus filhos.
35 0
23 1
18 2
11 3
15 4
9 5
13 6
44
Assim, podemos montar a seguinte tabela: i 2i+1 2i+2 i 2i+1 2i+2 i 2i+1 2i+2 0 1 2 1 3 4 2 5 2 35 23 18 23 11 15 18 9 13
HEAPSORT ETAPAS a) Montar a heap. A transformao feita do ltimo nvel da rvore para a raiz, colocando em cada n o elemento de maior chave entre ele e seus filhos, at que se obtenha a heap. b) Trocar o elemento da raiz (que possui a maior chave) com o elemento do n que est na ltima posio do vetor. A seguir isolar esse elemento e repetir o processo com os elementos restantes. Exemplo passo a passo:
0 1 2 3 4 5 6 7 8 9 520 450 254 310 285 179 652 351 423 861 285 i MF raiz 520 450 254 310 861 179 652 351 423 861 i 520 450 254 310 861 179 652 351 423 285 520 450 254 310 861 179 652 351 423 285 310
raiz i MF MF 520 450 254 423 861 179 652 351 423 285 i 520 450 254 423 861 179 652 351 310 285 i 520 450 254 423 861 179 652 351 310 285 254 raiz i MF MF 520 450 652 423 861 179 652 351 310 285 i 520 450 652 423 861 179 254 351 310 285
520 450 652 423 861 179 254 351 310 285 450
raiz i MF MF 520 861 652 423 861 179 254 351 310 285 i MF
45
520 861 652 423 450 179 254 351 310 285 520 861 652 423 450 179 254 351 310 285 520 raiz i MF 861 861 652 423 450 179 254 351 310 285 I MF MF 861 520 652 423 450 179 254 351 310 285
RVORE HEAP
TROCA V[0] COM V[9] 861 520 652 423 450 179 254 351 310 285 dir 285 520 652 423 450 179 254 351 310 861 dir 285 520 652 423 450 179 254 351 310 285 i MF MF raiz 652 520 652 423 450 179 254 351 310 i MF MF 652 520 285 423 450 179 254 351 310 dir 310 520 285 423 450 179 254 351 652 dir 310 520 285 423 450 179 254 351 310 i MF raiz 520 520 285 423 450 179 254 351 i MF MF 520 450 285 423 450 179 254 351 i 520 450 285 423 310 179 254 351 dir 351 450 285 423 310 179 254 520 dir 351 450 285 i MF 450 450 285 i 450 423 285 423 310 179 254 351 raiz 423 310 179 254 MF 423 310 179 254 i 450 423 285 351 310 179 254 dir 254 423 285 351 310 179 450 dir 254 423 285 351 310 179 254 i MF raiz
46
423 423 285 351 310 179 i MF 423 351 285 351 310 179 i 423 351 285 254 310 179 dir 179 351 285 254 310 423 dir 179 351 285 254 310 179 i MF raiz 351 351 285 254 310 i MF MF 351 310 285 254 310 i 351 310 285 254 179 dir 179 310 285 254 351
dir
254
i
179 254 285 dir 179 254 179 i MF raiz 254 254 i 254 179 dir
47
179 254 dir 179 254 285 310 351 423 450 520 652 861
Ordenado!!!
PASCAL: O ndice inicial do vetor 1, o sucessor esquerda do elemento de ndice i ser 2i e o da direita, 2i+1.
PROCEDURE REFAZHEAP( ESQ, DIR : INTEGER; VAR V: VETOR); VAR I, IND_MAIOR_FOLHA : INTEGER; RAIZ : ITEM; HEAP: BOOLEAN; BEGIN I := ESQ; IND_MAIOR_FOLHA := 2*I; RAIZ := V[I]; HEAP := FALSE; Encontrando WHILE (IND_MAIOR_FOLHA <= DIR) AND (NOT HEAP) DO a maior folha BEGIN IF (IND_MAIOR_FOLHA < DIR) THEN IF (V[IND_MAIOR_FOLHA].CHAVE < V[IND_MAIOR_FOLHA+1].CHAVE) THEN IND_MAIOR_FOLHA = IND_MAIOR_FOLHA+1; IF (RAIZ.CHAVE < V[IND_MAIOR_FOLHA].CHAVE) THEN BEGIN V[I] := V[IND_MAIOR_FOLHA]; Se a raiz for menor que I := IND_MAIOR_FOLHA; a maior folha, ocorre a IND_MAIOR_FOLHA := 2*I; troca. Volta e verifica se END sub-rvore continuar ELSE heap. HEAP := TRUE; END; {WHILE} V[I] := RAIZ; END; PROCEDIMENTO HEAPSORT (VAR V: VETOR; N : INTEGER); VAR ESQ, DIR : INTEGER; AUX : ITEM; BEGIN DIR := N; ESQ := N DIV 2; WHILE (ESQ > 0) DO BEGIN REFAZHEAP (ESQ, N, V); ESQ := ESQ-1; END; WHILE (DIR > 1) DO BEGIN AUX := V[1] ; V[1]:= V[DIR]; V[DIR] := AUX DIR := DIR-1; REFAZHEAP(1, DIR, V); END; END;
48
EM JAVA: O ndice inicial do vetor 0 (zero), o sucessor esquerda do elemento de ndice i ser 2i+1 e o da direita, 2i+2.
public void heapSort (){ int dir = nElem-1; int esq = (dir-1)/2; Item temp; while (esq >= 0){ refazHeap (esq, this.nElem-1); esq--; } while (dir > 0){ temp = this.vetor[0]; this.vetor [0] = this.vetor [dir]; this.vetor [dir] = temp; dir--; refazHeap(0, dir); } } private void refazHeap (int esq, int dir){ int i = esq; int maiorFolha = 2*i+1; Item raiz = this.vetor[i]; boolean heap = false;
Encontrando
a maior folha while ((maiorFolha <= dir) && (!heap)){ if (maiorFolha < dir) if (this.vetor[maiorFolha].getChave() < this.vetor[maiorFolha+1].getChave()) maiorFolha ++; if (raiz.getChave() < this.vetor[maiorFolha].getChave()) { this.vetor[i] = this.vetor[maiorFolha]; i = maiorFolha; Se a raiz for menor que maiorFolha = 2*i+1; a maior folha, ocorre a } troca. Volta e verifica se else sub-rvore continura heap = true; heap. } this.vetor[i] = raiz;
}
CONSIDERAES: Este algoritmo no estvel No recomendado seu uso para arquivos com poucos registros devido ao tempo necessrio para se construir a heap ANLISE DO ALGORITMO: Melhor caso seria o vetor em ordem decrescente Pior caso seria o vetor em ordem crescente
49
Como a complexidade no to simples de ser calculada, temos que, no caso mdio: C (n) = O(n logn) , bem como M(n) = O(n logn)
Quadro Comparativo = Tempo de Execuo N = 256 N = 2048 Mtodo Ordenado Aleatrio Invertido Ordenado Aleatrio Invertido Insero Direta 0.02 0.82 0.64 0.22 50.74 103.80 Seleo Direta 0.94 0.96 1.18 58.18 58.34 73.46 Bubblesort 1.26 2.04 2.80 80.18 128.84 178.66 Shakersort 0.02 1.66 2.92 0.16 104.44 187.36 Shellsort 0.10 0.24 0.28 0.80 7.08 12.34 Heapsort 0.20 0.20 0.20 2.32 2.22 2.12 Quicksort 0.08 0.12 0.08 0.72 1.22 0.76 Podemos concluir que: Em quase todos os casos o Bubblesort o pior deles. Isso s no acontece quando o arranjo est em ordem invertida, pois assim, o pior deles o Shakersort. Quando o arranjo est ordenado, os melhores so Insero Direta e Shakersort, sendo que ao aumentar o tamanho do arranjo, o Shakersort fica melhor do que o Insero. Para arranjos aleatrios e invertidos, o Quicksort o melhor. O heapsort no altera muito seu tempo de execuo ao alterar o tipo de entrada e, o seu tempo de execuo ao aumentar o tamanho do arranjo aumenta menos se compararmos com os outros mtodos. Podemos tambm observar as tabelas apresentadas pelo Prof. Nvio Ziviane que estuda 2 o comportamento de cinco desses algoritmos (Seleo e Insero O(n ) comparaes e Shell, Quick e Heap O(n logn) comparaes) ao ordenar arranjos de 500, 5.000, 10.000 e 30.000 registros.
1 2
50
Em cada tabela, no temos tempo real, mas um comparativo onde o mtodo que levou menos tempo para executar a ordenao recebeu valor 1 e os outros receberam valores relativos a ele. Assim, quem recebeu valor 2, levou o dobro de tempo do que quem recebeu valor 1. Ordenado Aleatrio Invertido 5000 10000 30000 500 5000 10000 30000 500 5000 10000 30000 1 1 1 11.3 87 161 40.3 305 575 1524 3066 16.2 124 228 29.3 221 417 6.8 7.3 8.1 1.2 1.6 1.7 2 1.5 1.5 1.6 1.6 6.3 6.8 7.1 1 1 1 1 1 1 1 1 20.8 22.4 24.6 1.5 1.6 1.6 1.6 2.5 2.7 2.7 2.9
500 Insero 1 Seleo 128 Shellsort 3.9 Quicksort 4.1 Heapsort 12.2
Podemos observar, pelas tabelas acima que: Shellsort, Quicksort e Heapsort tm a mesma ordem de grandeza; Se a entrada de dados for aleatria, o Quicksort o mais rpido para todos os tamanhos experimentados; Para entrada aleatria em arquivos pequenos (500 registros) o Shellsort mais rpido do que o Heapsort, mas quando o tamanho da entrada cresce, esta relao se inverte. O mtodo de Insero o mais rpido, para qualquer tamanho, se os elementos j esto ordenados (melhor caso) e o mais lento, para qualquer tamanho, se os elementos esto em ordem invertida (pior caso). Entre os algoritmos O(n ), o Insero o m elhor para todos os tamanhos aleatrios experimentados Foi feito tambm um experimento para saber a influncia da ordem inicial do arquivo sobre cada um dos trs mtodos eficientes. Para cada mtodo, tem -se tambm o tempo proporcional, ou seja, 1 o melhor tempo e os outros so relativos ao 1. SHELLSORT QUICKSORT HEAPSORT 5000 10000 30000 5000 10000 30000 5000 10000 30000 Ord 1 1 1 1 1 1 1.1 1.1 1.1 Inv 1.5 1.6 1.5 1.1 1.1 1.1 1 1 1 Ale 2.9 3.1 3.7 1.9 2.0 2.0 1.1 1.1 1.1
2
1. SHELLSORT ? sensvel ordenao ascendente ou descendente, ou seja, para arquivos de mesmo tamanho, executa mais rpido com arquivo ordenado ou invertido do que aleatrio. 2. QUICKSORT ? ssim como o shellsort, sensvel ordenao ascendente ou A descendente, ou seja, para arquivos de mesmo tamanho, executa mais rpido com arquivo ordenado ou invertido do que aleatrio. Mas o mais rpido se os elementos estiverem em ordem ascendente. 3. HEAPSORT ? raticamente no sensvel entrada. P 51
II.11 CONCLUSO
J INSERO: o mais interessante p ara arquivos com menos de 20 elementos. O mtodo estvel e seu comportamento melhor que o BUBBLESORT que tambm estvel. Sua implementao simples. Quando se deseja adicionar alguns elementos a um arquivo j ordenado e depois obter um outro arquivo ordenado, seu custo linear. J SELEO: Somente vantajoso quando a arquivo possui registros muito grandes, desde que o tamanho do arquivo no ultrapasse 1000 registros J SHELLSORT: o mtodo escolhido para a maioria das aplicaes por ser muito eficiente para arquivos com at 10000 registros. Para arquivos grandes, apesar de ser mais lento do que o Quicksort, ele demora apenas o dobro do tempo deste, mas, em compensao, sua implementao mais simples, fcil de funcionar corretamente e resulta em um programa pequeno. E, alm disso tudo, no possui um pior caso e, quando encontra um arquivo parcialmente ordenado trabalha menos. J QUICKSORT: o algoritmo mais eficiente para vrias situaes, mas um mtodo frgil, pois pode haver muita dificuldade para detectar erros de implementao. O algoritmo recursivo, necessitando de uma pequena quantidade de memria 2 adicional. No pior caso sua ordem O(n ) operaes. Se obtiver uma implementao robusta, ele deve ser o mtodo utilizado. necessrio ter cuidado ao escolher o piv. SOLUO: escolher uma pequena amostra do arranjo e usar a mediana da amostra como piv. Geralmente se usa uma amostra de 3 elementos. Melhoria: Se o subarquivo da chamada recursiva tiver menos que 25 elementos, pode-se usar Insero Direta nesse sub-arquivo. A melhoria chega a 20%. J HEAPSORT: um mtodo elegante e eficiente apesar de ser mais lento do que o QUICKSORT mas, no precisa de memria adicional. sempre O(n logn) portanto, bom para aplicaes que no podem tolerar variaes no tempo esperado, de acordo com a entrada.
II.12 EXERCCIOS
1) Preencha a tabela abaixo adequadamente: Algoritmo Seleo Direta BubbleSort ShakerSort Insero Direta Shellsort MergeSort QuickSort HeapSort Custo para o melhor caso M(n) C(n) Custo para o pior caso M(n) C(n) Observaes
52
2) Coloque em ordem crescente, o comportamento assinttico das funes mais utilizadas em anlise de algoritmos O(1) < O( ) < O( ) < O( ) < O( ) < O( ) < O( )
3) Em cada caso abaixo, diga qual algoritmo de ordenao, dentre os vistos, seria mais indicado para cada caso ? Justifique. a) Um vetor com 1000 registros inversamente ordenados. b) Um vetor com 10000 registros inversamente ordenados. c) Um vetor com 5000 registros, ordenados, e que pode sofrer poucas incluses ou remoes. d) Arquivo com 70 registros, sendo que estes registros so muito grandes, o que torna o custo de movimentao de itens crtico em relao a qualquer outra operao. e) Um arquivo com 500 registros, de 20 campos cada, ordenados em ordem inversa. f) Um arquivo com 750 registros quase ordenados. g) Um arquivo com 3.500 registros aleatrios. h) Um arquivo com 650 registros, ordenados, exceto o ltimo elemento que o menor de todos. i) Um arquivo com 1.500 registros, onde se deseja estabilidade. j) Um arquivo com 2.000 registros aleatrios.
4) Sugira um algoritmo para ordenao de uma lista simplesmente encadeada. Justifique. 5) Para um vetor pouco voltil, pequeno e com baixo potencial de crescimento, qual o algoritmo de ordenao, dentre os vistos, o mais indicado? Explique. 6) Se voc deseja ordenar vrios arquivos, de vrios tamanhos, podendo variar o tamanho dos registros, qual ou quais algoritmos de ordenao, dentre os vistos, usaria se houvesse restries quanto estabilidade? Justifique. 7) No problema (6), qual usaria se houvesse intolerncia para o pior caso, ou seja, no permite que a execuo demore muito mesmo que eventualmente? Justifique.
8) Supondo que voc estava trabalhando em um computador a ordenar um conjunto muito grande de nmeros inteiros, cada nmero formado de muitos dgitos, usando um mtodo O(n logn). O seu computador foi atacado por um vrus que alterou, aleatoriamente os 4 bits menos significativos de cada nmero. Voc quer ordenar novamente os novos nmeros. Escolha um algoritmo capaz de ordenar os novos nmeros em O (n). Justifique. 9) Suponha que voc tenha que ordenar vrios arquivos de 100, 500 e 2.000 nmeros inteiros. Para os trs tamanhos de arquivos necessrio realizar a ordenao no menor tempo possvel, utilizando um mtodo visto. a) Que algoritmo de ordenao voc usaria para cada tamanho de arquivo? Justifique b) Se for necessrio manter a estabilidade, que algoritmo de ordenao voc usaria para cada tamanho de arquivo? Justifique.
53
10) Suponha um vetor que ir armazenar informaes de telefones dos habitantes de uma determinada cidade. A finalidade do programa que utiliza este vetor realizar a leitura de todos os telefones e nomes das respectivas pessoas e ento realizar a ordenao para imprimir a lista telefnica. Qual o melhor algoritmo de ordenao para este caso. Justifique. 11) Suponha um site de busca que encontra todas as pginas relacionadas a uma determinada palavra. Este site deve ento ordenar todas as pginas encontradas pelo nmero de ocorrncias da palavra na pgina, ou seja, a pgina onde a palavra apareceu mais vezes dever ser a primeira da lista, e assim sucessivamente. Dos algoritmos estudados qual seria o melhor para utilizao neste site? Explique. 12) O que cada trecho de cdigo assinalado (A, B, C, D e E) faz no algoritmo abaixo.
public void heapSort (){ int dir = nElem-1; int esq = (dir-1)/2; Item temp; while (esq >= 0) refazHeap (esq--, this.nElem-1); A while (dir > 0){ temp = this.vetor[0]; this.vetor [0] = this.vetor [dir]; this.vetor [dir--] = temp; refazHeap(0, dir); }
} private void refazHeap (int esq, int dir){ int i = esq; int MaiorFolha = 2*i+1; Item raiz = this.vetor[i]; boolean heap = false; while ((MaiorFolha <= dir) && (!heap)){ if (MaiorFolha < dir) if (this.vetor[MaiorFolha].getChave()<this.vetor[MaiorFolha+1].getChave()) C MaiorFolha++; if (raiz.getChave() < this.vetor[MaiorFolha].getChave()) { D this.vetor[i] = this.vetor[MaiorFolha]; i = MaiorFolha; E MaiorFolha = 2*i+1; } else heap = true; } this.vetor[i] = raiz; }
13) Simule os mtodos vistos para organizar os vetores abaixo. a) Ao simular o Shellsort, utilize H = 5, H = 3 e H = 1: 05 10 09 07 14 08 20 02 06 18 01 54
b) Ao simular o Shellsort, utilize H = 4, H = 2 e H = 1: 30 20 15 12 22 18 07 09 11 14) Calcule o custo dos algoritmos abaixo: a) boolean procura (int[][] mat, int num){ int i=0, j; boolean achou = false; while (i<mat.length && !achou){ j = 0; while (j<mat[i].length && !achou){ if (mat[i][j] == num) achou = true; j++; } i++; } return achou; } b) void calculo (int[][] mat, int[] vet){ int i, j; for (i=0; i<mat.length; i++) for (j=0; j< mat[i].length; j++) vet[i] = vet[i] + mat[i][j]; } c) int maior (int[][] mat){ int temp, i, j; temp = mat[0][0]; for (i=0; i<mat.length; i++) for (j=0; j< mat[i].length; j++) if (mat[i][j] > temp) temp = mat[i][j]; return temp; } d) boolean simetrica (int[][] mat){ int i, j; for (i=0; i<mat.length; i++) for (j=0; j< mat[i].length; j++) if (mat[i][j] != mat[j][i] return false; return true; } 15) Coloque em ordem crescente as seguintes funes pela dominao assinttica. 2 2 log n A(n) = 50n B(n) = 3 n /log n D(n) = log n E(n) = 2 F(n) = log(n + 5/n) 55
Podemos tambm definir um item de busca como um campo (ou atributo) da tabela que pode ser usado para pesquisa, mas que no, necessariamente, seja a chave primria nem identifica de forma nica um elemento.
III.1.1 Estrutura em Pascal As estruturas trabalhadas so formadas por uma coleo de registros, que, por sua vez, so formados por um conjunto de campos. A estrutura de dados registro apresentada a seguir, onde o campo CHAVE a chave primria:
TYPE TPITEM = RECORD CHAVE : TPCHAVE; {outros campos} END;
Como neste captulo estudaremos pesquisa de dados na memria interna, uma forma possvel de armazenar uma tabela atravs do tipo vetor:
CONST MAXN = {valor mximo de registros na tabela} TYPE TABELA = RECORD ITEM : ARRAY[0..MAXN] OF TPITEM; N : INTEGER; {quantidade de registros do vetor} END;
57
III.1.2 Estrutura em Java As estruturas trabalhadas so formadas por uma coleo de objetos (Item), que, por sua vez, so formados por um conjunto de atributos. A estrutura de dados Item apresentada a seguir:
public class Item { private tipoChave chave; // outros atributos // construtor e mtodos para manipular os atributos dentre eles: public tipoChave getChave ( ){ return this.chave; } }
Onde o campo chave da classe Item a chave primria. Ao armazenar a tabela atravs de um array, temos:
public class Tabela{ private Item[] vetor; //referncia a um vetor de itens private int nElem; //nmero de itens de dados public Tabela (int tamanho){ //construtor this.vetor = new Item[tamanho]; this.nElem = 0; }// mtodos da classe }
public class ListaEnc { private No prim; //Pode ter outros atributos, como ult, qElem. public ListaEnc(){ this.prim = null; } }
58
CUSTO: Melhor caso: elemento pesquisado o ltimo C(n) = 1 III.2.1.2Procedimento Inicializa (Pascal)
PROCEDURE INICIALIZA (VAR TAB : TABELA); BEGIN TAB.N := 0; END;
59
III.2.1.5 Pesquisa seqencial em Vetor (Java) Em Java, no utilizaremos a sentinela para a implementao do algoritmo:
public int pesquisaSequencial (int chave){ int pos = this.nElem-1; while ((pos >= 0) && (this.vetor[pos].getChave() != chave)) { pos--; } return pos; }
CUSTO: Melhor caso: elemento pesquisado o ltimo C(n) = 1 Pior caso: elemento no existe no vetor C(n) = n
III.2.1.6 Procedimento Insere (Java) Este mtodo retorna false se houver erro ao inserir um elemento no vetor (vetor cheio), e true se a insero for bem sucedida.
public boolean inserir(Item elemento){ if (this.nElem == this.vetor.length) return false; else{ this.vetor[this.nElem++]= elemento; return true; } }
60
III.2.1.7 Procedimento Remove (Java) Este mtodo retorna false se houver erro ao remover um elemento no vetor (vetor vazio ou elemento no existe), e true se a remoo for bem sucedida.
public boolean remove (int chave){ int pos; if (this.nElem == 0) return false; else{ pos = pesquisaSequencial (chave); if (pos >= 0){ this.nElem--; this.vetor[pos] = this.vetor[this.nElem]; return true; } else return false; } }
CONSIDERAES:
! Este algoritmo a melhor soluo para problemas de pesquisa em tabelas com at
25 registros
! A Funo Pesquisa retorna o ndice do registro que contm a chave procurada. Se
necessria uma reformulao. Vamos ver agora como ficariam os algoritmos se usarmos a estrutura de lista encadeada:
III.2.2 Pesquisa seqencial em Lista Simplesmente Encadeada (LSE) Neste momennto, veremos a pesquisa sequencial em uma LSE, usando primeiro a linguagem Pascal e aps, usando Java.
61
PESQSEQ := P; END;
62
CUSTO: Melhor caso: elemento pesquisado o primeiro C(n) = 1 Pior caso: elemento no existe na lista C(n) = n
vetor. 63
Se a chave de busca for menor que a chave deste registro, ento o registro procurado deve estar na primeira metade da tabela; se maior, ento deve estar na segunda metade; se igual, a pesquisa foi realizada com sucesso.
! O processo deve ser repetido at se encontrar o registro (pesquisa com sucesso)
ou ficar apenas um registro com chave diferente da chave de pesquisa (pesquisa sem sucesso).
Exemplo: Pesquisando o nmero 3 Esq 3 5 6 8 9 1 2 3 4 5 Meio = (1 + 11) div 2 = 6 3 = V[ meio ] ? NO 3 < V[ meio ] ? SIM _ Dir = Meio - 1 Esq 3 5 6 8 9 1 2 3 4 5 Meio = (1 + 5) div 2 = 3 3 = V[ meio ] ? NO 3 < V[ meio ] ? SIM _ Dir = Meio - 1 Esq 3 5 6 8 9 1 2 3 4 5 Meio = (1 + 2) div 2 = 1 3 = V[ meio ] ? SIM _ RETORNA 1
12 6
18 7
20 8
24 9
29 10
Dir 35 11
12 6
18 7
20 8
24 9
29 10
Dir 35 11
12 6
18 7
20 8
24 9
29 10
Dir 35 11
Anlise do algoritmo: Melhor caso: C(n) = 1 , elemento procurado est no meio do vetor. Pior caso: C(n) = 2log2n, ele mento no existe no vetor Caso mdio: O(log2 n)
CONSIDERAES ! O custo para manter a tabela ordenada alto, pois a cada insero de forma ordenada ou a cada excluso, h um nmero alto movimentaes. Logo, no um mtodo indicado para arquivos volteis.
65
66
III.4.1 rvore Binria de Busca ABB ABB uma rvore binria onde os elementos menores que a raiz esto esquerda da mesma e os elementos maiores direita. arv Exemplo:
3 2 1 4
Caminhamento Central: Ao fazer o caminhamento central em uma ABB obtemos um vetor em ordem crescente. Este caminhamento feito da seguinte maneira: 1. Percorrer a sub-rvore esquerda 2. Visitar raiz 3. Percorrer sub-rvore direita
15 13 10 14 20 23 25 28
67
68
III.4.2 rvore Binria de Busca sem Balanceamento ABB Inicialmente vamos trabalhar com uma rvore binria de pesquisa sem realizar balanceamento
private NoArvore pesquisa (int chave, NoArvore no){ NoArvore temp; temp = no; if (temp != null){ if (chave < temp.getInfo().getChave()) temp = this.pesquisa (chave, temp.getEsq()); else{ if (chave > temp.getInfo().getChave()) temp = this.pesquisa (chave, temp.getDir()); } } return temp; }
69
70
III.4.2.6 Remoo (Pascal) Na remoo necessrio verificar trs situaes: 1. Remoo de um n folha o caso mais simples. Basta remover o n. 2. Remoo de um n com um nico filho Este tambm um caso simples. Basta fazer a raiz apontar para este nico filho. 3. Remoo de um n com dois filhos Neste caso, deve-se rearranjar a rvore para e nquadrar este caso em um dos anteriores. Isto feito trocando-se o n a ser removido pelo n mais direita da sub-rvore esquerda, ou pelo n mais esquerda da sub-rvore direita. Assim, cairemos em um dos casos mais simples.
PROCEDURE REMOO (CH : TPCHAVE; VAR ARV : TPARVORE); VAR P : APONTADOR; PROCEDURE ARRUMA (Q : APONTADOR; VAR R : APONTADOR); BEGIN IF (R^.DIR <> NIL) THEN ARRUMA (Q, R^.DIR) ELSE BEGIN Q^.ITEM := R^.ITEM; Q := R; R := R^.ESQ; DISPOSE (Q); END; END; { ARRUMA} BEGIN {REMOCAO} IF (ARV = NIL) THEN WRITELN (REGISTRO NAO ESTA NA ARVORE) ELSE IF (CH < ARV^.ITEM.CHAVE) THEN REMOCAO (CH, ARV^.ESQ) ELSE IF (CH > ARV^.ITEM.CHAVE) THEN REMOCAO (CH, ARV^.DIR) ELSE IF (ARV^.DIR = NIL) THEN BEGIN P := ARV; ARV := ARV^.ESQ; DISPOSE (P); END ELSE IF (ARV^.ESQ = NIL) THEN BEGIN P := ARV; ARV := ARV^.DIR; DISPOSE (P); END ELSE ARRUMA (ARV, ARV^.ESQ); END;
71
J Anlise: Depende do formato da rvore. Pior Caso: Chaves Inseridas em ordem crescente ou decrescente. Exemplo: 7, 8, 10, 18, 21, 24 C(n) = O(n) Melhor Caso: Chave de busca na raiz. C(n) = O(1) Caso Mdio : C(n) = O(log n) Pode-se evitar o pior caso, Como? Fazendo o balanceamento da rvore.
72
III.4.3 Balanceamento Como chegar a uma rvore balanceada atravs de uma rvore no balanceada? a) Fazer um caminhamento central, obtendo um vetor ordenado VO b) Construir um vetor balanceado, VB, a partir de VO. c) Criar a rvore binria de pesquisa balanceada a partir de VB.
Exemplo 1: 18 10 7 8
arv
21 24
VO 7
8 10 18 21 24
Observao : ind o ndice de VO, ou seja, a posio que ser inserido o item encontrado na rvore. ind inicializado com 0 no programa que chama o procedimento. O tipo vetor o mesmo definido no captulo anterior (array[1..n] of TpItem)
73
III.4.3.3 Construo da rvore balanceada (Pascal) Pega-se o registro localizado no meio do vetor ordenado e vai repetindo o processo rvore 10 7 8 18 21 24
arv
VB 7
8 10 18 21 24
PROCEDURE VET_BALANCEADO ( VO : TPVETOR; VAR ARV : TPARVORE; INIC, FIM : INTEGER ); VAR MEIO : INTEGER; BEGIN IF ( FIM >= INIC ) THEN BEGIN MEIO := (INIC + FIM) DIV 2; INSERO (VO[MEIO], ARV) ; VET_BALANCEADO ( VO, VB, INIC, MEIO - 1); VET_BALANCEADO ( VO, VB, MEIO + 1, FIM); END; END;
Observao : inic a posio do primeiro elemento armazenado em VO e fim a posio do ltimo elemento em VO.
74
private void Balancear (TabelaOrd vet, Arvore temp, int inic, int fim){ int meio; if (fim >= inic){ meio = (inic+fim)/2; temp.insere(vet.getElemVetor(meio)); this.Balancear (vet, temp, inic, meio - 1); this.Balancear (vet, temp, meio + 1, fim); } }
Assim, para cada n podemos definir um fator de balanceamento (FB), que vem a ser um nmero inteiro igual a: FB(nodo p) = altura(subrvore direita p) - altura(subrvore esquerda p) Seja um n qualquer da rvore, apontado por P:
!se FB(n) = 0, as duas subrvores tm a mesma altura; !se FB(n) = -1, a subrvore esquerda mais alta que a direita em 1; !se FB(n) = +1, a subrvore direita mais alta que a esquerda em 1.
Como, na prtica, no podemos prever qual ser a ordem de entrada dos valores, e, muito menos, alterar essa ordem para que ela seja conveniente construo de uma rvore balanceada, a soluo adotar um algoritmo que, a cada insero, faa as correes necessrias para manter sempre a rvore como uma rvore AVL, ou seja, onde qualquer n n tenha | FB(n) | <= 1. A vantagem de uma rvore AVL sobre uma degenerada (rvore no formato LSE) est na maior eficincia nas suas operaes de busca, pois, sendo a altura da AVL bem menor, o nmero necessrio de comparaes diminui sensivelmente. Por exemplo, numa rvore degenerada de 10.000 ns, so necessrias, em mdia, 5.000 comparaes, numa busca; numa rvore AVL, com o mesmo nmero de ns, essa mdia baixa para 14. Exemplo de rvore AVL:
1 8 0 0 4 10 +1 4 10 8 0
Objetivo principal: como deixar sempre a rvore balanceada? Insero em uma rvore AVL A idia geral da insero : 1) Inserir um n na rvore binria de pesquisa 2) Procurar, a partir do n inserido, se existe algum n desbalanceado. 3) A partir do n desbalanceado corrigir o balanceamento com rotaes. 3.1) Escolher entre rotao simples ou dupla
76
No gera desbalanceamento.
INSERO DA CHAVE 5 Esta operao desbalanceou a rvore. O que fazer? Resposta: uma rotao simples para a direita.
INSERO DO 30
No causa desbalanceamento.
INSERO DO 25
Aqui temos uma rotao simples para a direita entre as chaves 25 e 30 e depois uma rotao para a esquerda envolvendo as chaves 20, 25 e 30. uma rotao dupla para a esquerda. 77
INSERO DO 27
Aqui temos uma rotao simples para a esquerda envolvendo toda a rvore. INSERO DO 28
Aqui temos uma rotao simples para a esquerda entre as chaves 27 e 28 e depois uma rotao para a direita envolvendo as chaves 30, 27 e 28. uma rotao dupla para a direita. Quando fazer rotao simples? o Fator de balanceamento com mesmo sinal o Rotao para esquerda -> sinais do FB positivos o Rotao para direita -> sinais do FB negativos Quando fazer rotao dupla? o Fator de balanceamento com sinais trocados o Rotao dupla para direita -> pai e o filho + o Rotao dupla para esquerda -> pai + e o filho
78
Procedimentos para se insero em rvore AVL: 1) Procedimento para realizar ROTAO DIREITA (RD) ou ROTAO DUPLA DIREITA (RDD)
PROCEDURE ROTDIR (VAR ARV : TP_AVL; VAR H: BOOLEAN); VAR AUX1, AUX2 : TP_AVL; BEGIN AUX1 := ARV^.ESQ; IF (AUX1^.FB = 1) THEN BEGIN ARV^.ESQ := AUX1^.DIR; Faz RD AUX1^.DIR := ARV; ARV^.BAL := 0; ARV := AUX1; END ELSE BEGIN AUX2 := AUX1^.DIR; AUX1^.DIR := AUX2^.ESQ; Faz RDD AUX2^.ESQ := AUX1; ARV^.ESQ := AUX2^.DIR; AUX2^.DIR := ARV; IF (AUX2^.FB = 1) THEN ARV^.FB:= 1 Recalcula o FB do n direita na nova rvore ELSE ARV^.FB := 0; IF (AUX2^.FB = 1) THEN AUX1^.FB := 1 Recalcula o FB do n esquerda na nova rvore ELSE AUX1^.FB := 0; ARV := AUX2; END; ARV^.BAL := 0; A raiz ter FB = 0 H := FALSE; END;
79
2) Procedimento para realizar ROTAO ESQUERDA (RE) ou ROTAO DUPLA ESQUERDA (RDE)
PROCEDURE ROTESQ (VAR ARV : TP_AVL; VAR H: BOOLEAN); VAR AUX1, AUX2 : TP_AVL; BEGIN AUX1 := ARV^.DIR; IF (AUX1^.FB = 1) THEN BEGIN ARV^.DIR := AUX1^.ESQ; AUX1^.ESQ := ARV; Faz RE ARV^.BAL := 0; ARV := AUX1; END ELSE BEGIN AUX2 := AUX1^.ESQ; AUX1^.ESQ := AUX2^.DIR; Faz RDD AUX2^.DIR := AUX1; ARV^.DIR := AUX2^.ESQ; AUX2^.ESQ := ARV; IF (AUX2^.FB = 1) THEN ARV^.FB:= 1 Recalcula o FB do n esquerda na nova rvore ELSE ARV^.FB := 0; IF (AUX2^.FB = 1) THEN AUX1^.FB := 1 Recalcula o FB do n direita na nova rvore ELSE AUX1^.FB := 0; ARV := AUX2; END; ARV^.BAL := 0; A raiz ter FB = 0 H := FALSE; END;
80
81
82
4) Mtodo para realizar ROTAO DIREITA (RD) ou ROTAO DUPLA DIREITA (RDD)
private Nodo rotaoDireita (Nodo no){ Nodo temp1, temp2; temp1 = no.getEsq(); if (temp1.getFatorBalanceamento() == -1){ no.setEsq(temp1.getDir()); Faz RD temp1.setDir(no); no.setFatorBalanceamento((byte)0); no = temp1; } else { temp2 = temp1.getDir(); temp1.setDir(temp2.getEsq()); Faz RDD temp2.setEsq(temp1); no.setEsq(temp2.getDir()); temp2.setDir(no); if (temp2.getFatorBalanceamento() == -1) Recalcula o FB do n direita no.setFatorBalanceamento((byte)1); na nova rvore else no.setFatorBalanceamento((byte)0); if (temp2.getFatorBalanceamento() == 1) temp1.setFatorBalanceamento((byte)-1); Recalcula o FB do n esquerda na nova rvore else temp1.setFatorBalanceamento((byte)0); no = temp2; } no.setFatorBalanceamento((byte)0); A raiz ter FB = 0 this.h = false; return no; }
5) Mtodo para realizar ROTAO ESQUERDA (RE) ou ROTAO DUPLA ESQUERDA (RDE)
private Nodo rotaoEsquerda (Nodo no){ Nodo temp1, temp2; temp1 = no.getDir(); if (temp1.getFatorBalanceamento() == 1){ no.setDir (temp1.getEsq()); temp1.setEsq(no);
83
no.setFatorBalanceamento((byte)0); no = temp1; } else { temp2 = temp1.getEsq(); temp1.setEsq(temp2.getDir()); temp2.setDir(temp1); no.setDir(temp2.getEsq()); temp2.setEsq(no); if (temp2.getFatorBalanceamento() == 1) no.setFatorBalanceamento((byte)-1); else no. setFatorBalanceamento((byte)0); if (temp2. getFatorBalanceamento() == -1) temp1. setFatorBalanceamento((byte)1); else temp1. setFatorBalanceamento((byte)0); no = temp2; } no.setFatorBalanceamento((byte)0); this.h = false; return no; }
84
III.6.1 Funo de transformao (Funo HASHING) Um exemplo de funo de transformao: H( K ) = K mod m. Onde: o K o nmero a ser transformado (pode ser a chave) o m um nmero primo maior ou igual a quantidade de registros a serem armazenados. Esta funo uma das mais utilizadas. Devemos ter cuidado na escolha do valor de m. Ele deve ser um nmero primo, mas no qualquer primo. Devem ser evitados os nmeros primos obtidos a partir de:
i b j
Onde b a base de um conjunto de caracteres. Geralmente, b 64 para BCD; 128 para ASCII; 256 para EBCDIC ou 100 para alguns cdigos decimais. i e j so pequenos inteiros. Exemplo: 100 registros, quais nmeros no deveriam ser escolhidos? 101 deveria ser evitado pois: 100 + 1 = 101 103 deveria ser evitado pois: 100 + 3 = 103
1 1
Java
public int Hashing (int chave, int M){ return chave/M; }
III.6.1.2 Se a chave for alfanumrica deve-se transforma-la em numrica: Uma possibilidade, que no a melhor, fazer a transformao a seguir:
FUNCTION HASHING (CHAVE : STRING[N]; M : INTEGER): INTEGER; VAR SOMA, I : INTEGER; BEGIN SOMA := 0; FOR I := 1 TO N DO SOMA := SOMA + ORD (CHAVE[I]); HASHING := SOMA MOD M; END;
85
Java
public int Hashing (String chave){ char carac; int i, soma=0; for (i=0; i<chave.length(); i++){ carac = chave.charAt(i); soma += Character.getNumericValue(carac); } return soma; }
III.6.2 Tratamento de colises Exemplo 1: Chaves entre [100 , 500]; quantidade mxima de registros N = 12 maior ou igual a 12 m = 13 Chaves a serem inseridas: 102; 200; 196; 53 ! 102 mod 13 = 11 ! 200 mod 13 = 5 Chave Endereo 102 11 200 5 196 1 53 1 ! 196 mod 13 = 1 ! 53 mod 13 = 1 a nmero primo
Pode-se observar que h colises. Como trat-las? O tratamento pode ser feito atravs do mecanismo de armazenamento: III.6.2.1 Endereamento Aberto um dos mtodos mais simples. possvel utilizar este mtodo quando h N registros para armazenar em uma tabela de tamanho M, onde M > N. Utiliza-se um vetor de ndices entre o intervalo [0, m-1], as chaves que colidem so armazenadas no prximo ndice vazio. Portanto, o exemplo anterior ficaria:
102 11 11
200 5 5
196 1 1
53 1 2
86
Cinthia C L Caliari
OBS.: Uma funo hashing, que transforma uma chave x em um endereo base h(x) dita ideal, se produzir um nmero baixo de colises, se for facilmente computvel e se todas as posies tiverem a mesma probabilidade de serem ocupadas (uniforme). Exemplo 2: Seja uma tabela com, no mximo, 53 registros, sendo que a chave primria possui 3 dgitos. Para mapear o domnio das possveis chaves (000 at 999) na tabela de 53 entradas (0 at 52), usaremos a seguinte funo Hashing: H(K) = K mod 53 Assim, teremos o seguinte mapeamento:
Chave
383
487 10
235 23
527 50
510 33
320 2
203 44
108 2
563 33
646 10
063 10
Endereo 12
Portanto, este exemplo ficaria: Chave Endereo End. Efetivo 383 12 12 487 10 10 235 23 23 527 50 50 510 33 33 320 2 2 203 44 44 108 2 3 563 33 34 646 10 11 063 10 13
Neste caso, segundo Knuth (1973), o custo mdio de uma pesquisa com sucesso
1 1 C (n) = 1 + n 2 1 m
onde Custo: Melhor caso: C(n) = O(1) Pior caso: C(n) = O(n) Caso mdio: C(n) = O(1) 87 n = nmero de registros e m = primo adotado na funo hashing
Cinthia C L Caliari
Se os registros no forem espalhados de forma razovel o tempo necessrio para novas pesquisas ser maior, pois medida que a tabela vai ficando cheia, a nova chave inserida tende a ocupar uma posio na tabela que esteja vizinho a outras posies j ocupadas, deteriorando o tempo necessrio para novas pesquisas. Isto pode ser visto na tabela a seguir: N/M C(n) 0.10 1.06 0.25 1.17 0.50 1.50 0.75 2.50 0.90 5.50 0.95 10.50
III.6.2.2 Vetor Encadeado Neste mtodo, todas as chaves transformadas, que colidem no mesmo endereo, so colocadas em uma lista encadeada. Ao ser calculado o endereo, a busca restringe-se lista encadeada correspondente lista que est na posio calculada do vetor.
1 196 2 53
III.7 NIL
m1
A estrutura de dados lista encadeada utilizada apresentada abaixo: Observe que esta estrutura a mesma para qualquer linguagem. 88
Cinthia C L Caliari
TYPE TPITEM = RECORD CHAVE : TPCHAVE; {outros campos} END; APONTADOR = ^CELULA;
CELULA = RECORD ITEM : TPITEM; PROX : APONTADOR; END; TPLISTA = RECORD PRIM, ULT : APONTADOR; END; TPDICIONARIO = ARRAY [1..M] OF TPLISTA;
Custo: Melhor caso: C(n) = 1 Pior caso: C(n) = n Caso mdio: C(n) = O(1) Vantagens do vetor encadeado sobre o endereamento aberto? {o aluno dever responder}
III.8 EXERCCIOS
1) Suponha que: a) Exista um conjunto de dados com elevada atividade e pequeno potencial de crescimento. b) Exista um conjunto de dados extremamente voltil, com elevado potencial de crescimento. Deseja-se obter o menor tempo possvel de resposta. Que tipo de algoritmo de pesquisa voc indicaria para os casos a e b ? Por que ?
2) Entre os seguintes mtodos de pesquisa: Pesquisa seqencial em tabela desordenada (vetor), pesquisa binria em tabela ordenada (busca binria) e rvore binria de pesquisa (vista em estrutura de dados), avalie para as situaes abaixo, qual o mtodo de pesquisa mais indicado, justificando. a) Processamento de consultas a um conjunto de dados com cerca de 500 registros, sendo este conjunto de baixa atividade, pouco voltil e com pequeno potencial de crescimento. b) Pesquisa a um conjunto de dados com 1000 registros, elevado potencial de crescimento e mdia atividade.
89
Cinthia C L Caliari
3) Para os casos abaixo, diga qual o algoritmo de pesquisa mais adequado, justificando. a) Suponha um conjunto de 5.500 elementos, com nenhum potencial de crescimento, baixa volatilidade e alta atividade. b) Suponha que haja um conjunto de 10.000 dados com alto potencial de crescimento, e muita atividade. c) Suponha que haja um conjunto de 30 elementos muito voltil, nenhum potencial de crescimento e com pouca atividade. d) Suponha que haja um conjunto de 5.000 elementos com alta atividade e muito voltil, mas baixo potencial de crescimento. 4) Considere as tcnicas de pesquisa seqencial, pesquisa binria e rvore de pesquisa balanceada e no balanceada. a) Descreva as vantagens e desvantagens de cada um dos mtodos acima. Em que situaes voc usaria cada um deles? b) D a ordem do melhor e do pior caso esperado de tempo de execuo em cada um deles.
5) Qual a principal propriedade de uma rvore binria de pesquisa? 6) Se as chaves Q U E S T A O F C I L fossem inseridas em uma rvore binria inicialmente vazia: a) Desenhe a rvore binria resultante. b) Desenhe as rvores resultantes das retiradas dos elementos E depois U da rvore do item (a). c) Desenhe a rvore binria balanceada resultante da questo inicial.
7) Relacione a coluna da direita com a da esquerda. [ a ] rvore Binria de Busca [ b ] Tabela Hashing [ c ] Pesquisa Sequencial [ ] Conjunto de dados onde o acesso rpido essencial. Este conjunto de dados esttico. [ ] Um conjunto de 20 registros. [ ] Deseja acesso rpido as informaes e exibio dos dados ordenados de forma eficiente.
8) Suponha que um programa deva ser implementado para armazenar 60 registros em um vetor. Este vetor utilizar o mtodo de pesquisa hashing. Defina a funo de transformao hashing, justificando. Exemplo: chave mod M. Voc dever definir o valor de M. 9) Cite as duas formas de se tratar c olises em uma tabela hashing. Qual das duas a mais eficiente? Justifique.
10) Construir uma rvore AVL com onde os elementos a seguir so inseridos na ordem em que aparecem: 60, 40, 20, 50, 56, 10, 65, 53, 68, 58, 51.
90
Cinthia C L Caliari
11) Seja a rvore AVL a seguir, insira as chaves: 23, 15 e 12, 17.
20
10
30
25
35
12) Suponha as seguintes chaves: 45, 66, 47, 26, 7, 10 a)Defina a equao hashing, justificando. b)Como eles ficariam armazenados em um vetor considerando a utilizao do endereamento aberto? Suponha que a ordem de insero na tabela seja a ordem em que as chaves aparecem acima (da esquerda para a direita), ou seja, o primeiro elemento a ser inserido seria o 45, o segundo 66, e assim por diante. c) Considere agora um vetor por encadeamento, como ficaria a sua configurao? (desenhe o vetor encadeado com os elementos inseridos na ordem apresentada acima). 13) Uma tabela Hash Interna tem 30 posies (0..29). As chaves so inteiros e a funo hashing h(i) = i mod 30 usada, com endereamento aberto. Se os elementos com chaves 91, 240, 31, 122, 63, 150, 35 so inseridos, nesta ordem, em uma tabela inicialmente vazia, responda: a) Faa o vetor correspondente tabela Hash acima. b) qual o nmero de comparaes que devem ser realizadas para achar o inteiro 150? c) Qual o elemento que est na posio 2 do vetor?
14) Supondo que deve ser feita uma tabela Hash com 700 elementos, usando endereamento aberto. Qual o tamanho ideal do vetor para que diminua o nmero de colises sem desperdiar muita memria? E usando vetor encadeado? Justifique.
15) Implemente um procedimento que dever inserir um item em um vetor que implementa o endereamento aberto. O tratamento de colises dever ser feito da seguinte maneira: O vetor ter tamanho de 0 at (m-1) + inteira(20%(m-1)) , onde os 20% armazenaro os elementos que colidirem. Exemplo: N = 11; M = 13; o vetor ir de zero a 12 + inteira(20%.12) = 12 + inteira (2.4) = 12 + 2 = 14 Supor chaves: 102, 196 e 53: 102 mod 13 = 11 196 mod 13 = 1 53 mod 13 = 1 -> colidiu ser armazenado na posio 13 (rea de colises)
196 1 2
102 10 11 12
53 13
14
91
Cinthia C L Caliari
IV.2 HISTRIA
Os primeiros projetos de estruturas de arquivos assumiam que os dados estariam em fitas: o acesso era seqencial, e o custo do acesso era diretamente proporcional ao tamanho do arquivo. Entretanto, rapidamente os arquivos cresceram de modo inaceitvel para o processamento atravs de acesso seqencial. 92
Cinthia C L Caliari
Dispositivos como discos e tambores apareceram, o que permitiu a associao de ndices aos arquivos. Os ndices permitem guardar uma lista de chaves/ponteiros em um arquivo menor, que podem ser pesquisados mais rapidamente. Dada a chave associada ao registro procurado, a busca no ndice retorna um ponteiro para o registro no arquivo principal, e a informao pode, ento, ser obtida diretamente. ndice - um arquivo auxiliar que facilita a recuperao de informao no arquivo principal, que o arquivo de dados. ndices simples resultam nos mesmos problemas quando crescem demais e tornam-se difceis de manter, principalmente no caso de arquivos dinmicos, nos quais as chaves mudam todo o tempo. No incio dos anos 60 surgiu a idia de usar rvores como soluo para estruturar os ndices. O problema que as rvores tendem a crescer de maneira desigual medida que as chaves so inseridas e removidas (ficam desbalanceadas). Em 1963 surgiram as rvores AVL, que so timas para estruturar dados em RAM. Pesquisadores logo pensaram em utilizar algo parecido para a estrutura de arquivos. Entretanto, mesmo rvores perfeitamente balanceadas exigem muitos acessos para localizar um dado registro. Era, portanto, necessrio encontrar um mecanismo de armazenar em cada n da rvore um bloco do arquivo contendo o maior nmero possvel de registros. Mais de dez anos de trabalho foram necessrios para chegar soluo, as chamadas B-trees, ou rvores-B. Um problema era que a metodologia requerida para arquivos era muito diferente da utilizada em RAM. rvores AVL crescem de cima para baixo enquanto que rvores-B crescem de baixo para cima! As rvores-B permitem um excelente desempenho na busca por registros do arquivo, ao custo de no mais se poder acessar sequencialmente o arquivo de modo eficiente. A soluo quase imediata foi encontrada com a adio de uma lista encadeada no nvel inferior da vore-B, nesse caso batizada de rvore-B+. Em termos prticos, rvores-B+ garantem o acesso a um registro mantido em um arquivo com milhes de entradas com apenas trs ou quatro acessos ao disco!!! Por mais de dez anos essas rvores formaram a base para a maioria dos sistemas de arquivo comerciais... A capacidade de acessar um registro em 3 ou 4 acessos um aspecto muito bom, mas o objetivo ideal era precisar de apenas 1 acesso.... A tcnica Hashing uma boa maneira de atingir este objetivo se estivermos trabalhando com arquivos cujo tamanho no alterado. H muito tempo ndices e hashing so combinados para garantir acesso eficiente a arquivos estticos. A tcnica conhecida por Dynamic Hashing, que pode ser aplicada a arquivos dinmicos eficientemente, relativamente recente.
Se fossemos pensar em uma linguagem (com limitao de memria): 640 Kbytes de heap = 655.360 1 n AVL = 2 apontadores (8 bytes) + inteiro:chave (2 bytes) + inteiro : FB (2 bytes) + ndice do arquivo (4 bytes) = 16 bytes Conseguiramos armazenar no mximo 40.960 ns 93
Cinthia C L Caliari
Para entendermos melhor como funciona o mecanismo de trabalho com arquivos precisamos entender onde eles so armazenados e como so acessados.
94
Cinthia C L Caliari
Memria Terciria Tempo de leitura e escrita muito alto. Fitas (seqncias) Jukeboxes de discos ticos Silos de fitas O acesso ao meio tercirio pode ser cerca de 1000 vezes mais lento que a memria secundria mas sua capacidade pode ser cerca de 1000 vezes maior. _Armazenamento Voltil x No Voltil Memria principal voltil Novos chips de memria chamados de memria flash no volteis. _Entendendo melhor os DISCOS (HD) Algumas caractersticas dos HDs Rotao ex: 5400 rpm: 1 rotao a cada 11 milisegundos. N de lminas (ex. 5 a 15 discos 30 superfcies) N de trilhas (ex.10.000 trilhas por superfcie) N de bytes por trilha (ex. 10 ) o 500 setores/trilha o 512 a 4096 bytes Gravao ou leitura de dados no HD feita por blocos. Controladores esto mais parecidos com os computadores, tendo processadores e memrias, podendo armazenar uma trilha inteira em sua memria. Modificao (alterao) envolve leitura, alterao e gravao-> processo + demorado. Controladora de disco responsvel por: Acionamento mecnico Seleciona uma superfcie Eixo giratrio Transferir os bits Tempos: Posicionar na trilha correta: 12 a 14 milisegundos em pcs e 8 ou 9 em servidores. Localizar e transferir um bloco do disco para a ramo: 12 a 60 milisegundos.
5
95
Cinthia C L Caliari
Figura 1: (a) Viso interna de um HD. (b) Superfcie de um disco. Fonte: [GARCIA-MOLINA, ULLMAN e WIDOM, 2001].
Cinthia C L Caliari
Um bloco pode variar de 512 a 4096 bytes [ELMASRI e NAVATHE, 2002]. Em se tratando de um BD, um componente do SGBD (gerenciador de buffers) responsvel por particionar a memria principal em buffers. Isto deve ocorrer de tal modo que a quantidade de buffers caiba na memria principal. Definies importantes: Organizao spanned: quando permitido que um registro seja maior que um bloco, neste caso haver ao final do bloco um ponteiro para o prximo bloco que contm o restante do registro. Organizao no-spanned: quando no permitido que um arquivo seja maior que o bloco.
IV.5 ARQUIVOS
Trabalharemos aqui com arquivos que contm uma seqncia de registros. Um arquivo composto de registros de tamanhos fixos ou variveis. Exemplos de tamanho varivel: Um campo nome pode ter um tamanho varivel. Arquivos de registros variantes. E outros. Um header de arquivo ou descritor de arquivo contm informaes sobre o mesmo, como: endereo no disco dos blocos que compe o arquivo, descries de registros, etc. Para pesquisar um registro em disco, por exemplo, um ou mais blocos so copiados para os buffers da memria principal. Os programas ento pesquisam o registro ou os registros desejados dentro dos buffers, at que o elemento seja encontrado ou at que os blocos terminem. O objetivo de uma boa organizao de arquivos localizar o bloco que contm um registro desejado com o nmero mnimo de transferncias de blocos.
IV.5.1 Arquivo Seqencial Os registros so organizados somente baseando-se em suas localizaes fsicas sucessivas no arquivo e, so lidos e atualizados na ordem em que aparecem. Ou seja, para acessar o n-simo registro, necessrio acessar os (n 1) anteriores. Se o arquivo no estiver ordenado, as a incluso em um arquivo ordenado implicar na necessidade de fazer uma feitas em disco, no necessitam de arquivos em fita. incluses podem ser feitas no final do arquivo. Mas ou excluso (no arquivo ordenado ou no) pode nova cpia do arquivo. J as atualizaes, quando nova cpia. Ao contrrio do que acontece com
Este tipo de organizao utilizado em arquivos para aplicaes de elevada atividade e pequena volatilidade. 97
Cinthia C L Caliari
IV.5.2 Arquivo Seqencial-Inde xado So aqueles arquivos onde se utiliza uma estrutura de acesso auxiliar chamada de ndice, que so utilizados para acelerar a recuperao de registros em resposta a determinadas condies de pesquisa. So projetados para aplicaes que requerem acessos seqencial e direto eficientes. A entrada do ndice formada por dois campos principais: um campo chave que conter o elemento a ser pesquisado e outro campo contendo a posio do registro no arquivo ou a posio do bloco que contm o arquivo. Essa entrada ocupa um espao bem menor do que o registro de dados correspondente, e faz com que a rea ocupada pelo ndice seja menor do que aquela ocupada pelos dados, com isso a pesquisa sobre um ndice pode ser feita com maior rapidez. Quando o ndice contm um registro para cada registro do arquivo ele chamado de ndice denso, quando o ndice possui um registro que armazena uma entrada para um bloco do arquivo ele chamado de ndice no denso ou esparso. Exemplos de organizaes para este tipo de arquivo: Uso de AVL (j estudado no captulo anterior) contendo a posio do registro no arquivo. Pesquisa Binria (vetor) contendo a posio do registro no arquivo. Apresentaremos algumas organizaes: a. ndices Principais ndice principal um arquivo ordenado cujos r gistros possuem dois campos: campo e chave e um campo que armazena a posio do bloco onde aquela chave est no arquivo. Este ndice contm o primeiro registro de cada bloco do arquivo (registro ncora). Como pesquisar? Pesquisa binria (O(log2n)) Problemas: Incluso ou excluso. Arquivos ordenados
Exemplo: Arquivo com 30000 registros no-spanned Registro = 100 bytes Bloco de 1024 bytes.
98
Cinthia C L Caliari
Teramos ento: 10 registros por bloco. 3000 blocos Uma pesquisa binria precisaria em mdia de log23000 = 12 acessos (sem ndice principal) Com ndice principal: arquivo de ndice: chave = 9 bytes, ponteiro = 6 bytes. Bloco = 1024 bytes 68 registros por bloco teria 3000 registro que ser igual a quantidade de blocos do arquivo original. Teria 45 blocos para o ndice principal. Uma pesquisa binria precisaria em mdia de log245 = 6 acessos (para buscar os blocos do ndice principal) e teria mais um acesso para buscar o bloco do arquivo. Veja, agora, o diagrama de acesso: Nmero Endereo 0 1 1000 2 3 4 5 6 7 8 9 1100 1400 1600 1850 1975 2400 2500 2950 2 4 6 8 10 12 14 16 Nmero 1000 1075 1100 1350 1400 1480 1600 1800 1850 1950 1975 2200 2400 2450 2500 2700 2950 3150 Nome Ademar ngela Antonio Csar Cludia Darci Diogo Edlson Edmundo Flvio Genaro Helena Iara Luiz Marta Ramon Sandra Sonia Idade Salrio 25 5000 0 22 28 25 30 26 35 34 26 39 33 25 23 38 27 34 25 28 6000 8500 9000 8000 7500 5000 6500 5500 9000 8000 8500 6000 7000 6500 7500 9000 7500 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
99
Cinthia C L Caliari
Com esta organizao, a localizao de um registro por meio de um argumento de pesquisa passa a ser feita em duas etapas: na primeira consultado o ndice e determinado o bloco no qual deve estar o registro e na segunda o bloco selecionado pesquisado, sendo localizado o registro desejado. b. ndices de Clustering Este ndice utilizado em arquivos originais que esto ordenados onde o campo de pesquisa no chave, ou seja, pode ser repetido. Um exemplo que podemos dar quando se deseja pesquisar em um arquivo as pessoas que possuem salrio igual a R$ 1000,00. O campo salrio o de pesquisa e pode estar repetido nos diferentes registros do arquivo. Exemplo: Arquivo de ndice de Clustering chave ponteiro 1 2 3 4 5 6
Arquivo original
Chave Outros campos
1 1 2 2 3 4 5 5 5 6 6
c.
ndices Secundrios um arquivo ordenado com 2 campos: 1 chave e um ponteiro. Tal chave nica. Este ndice um ndice denso. Nesta organizao os dados do arquivo original no precisam estar ordenados apenas os dados do arquivo de ndice.
100
Cinthia C L Caliari
5 10 7 2 8 9 3 4 1 6
Exemplo: Arquivo com 30000 registros no-spanned Registro = 100 bytes Bloco de 1024 bytes. Teramos ento: 10 registros por bloco. 3000 blocos Uma pesquisa seqencial, em mdia, seu custo seria n/2, ou seja: 1500 blocos. Com ndice secundrio: arquivo de ndice: chave = 9 bytes, ponteiro = 6 bytes. Bloco = 1024 bytes 68 registros por bloco teria 30000 registro que ser igual a quantidade de registros do arquivo original. Teria 442 blocos para o ndice secundrio. Uma pesquisa binria precisaria em mdia de log2442 = 9 acessos (para buscar os blocos do ndice secundrio) e teria mais um acesso para buscar o bloco do arquivo. 101
Cinthia C L Caliari
Como implementar um arquivo de ndice secundrio para um arquivo que no est ordenado, e o campo a ser considerado para a pesquisa se repete?
Arquivo original
Chave Outros campos
5 2 4 2 4 5 3 4 1 5 2
d.
ndices Multinvel Nesta organizao utiliza-se mais de um arquivo de ndice. A idia aqui diminuir o acesso a bloco da pesquisa binria que acessa, em mdia, cerca de O(log2n) blocos. Exemplo: Arquivo com 30000 registros no-spanned Registro = 100 bytes Bloco de 1024 bytes. Teramos ento: 10 registros por bloco. 3000 blocos Uma pesquisa seqencial, em mdia, seu custo seria n/2, ou seja: 1500 blocos. 102
Cinthia C L Caliari
Com ndice secundrio: arquivo de ndice: chave = 9 bytes, ponteiro = 6 bytes. Bloco = 1024 bytes 68 registros por bloco teria 30000 registro que ser igual a quantidade de registros do arquivo original. Teria 442 blocos para o ndice secundrio. Uma pesquisa binria precisaria em mdia de log2442 = 9 acessos (para buscar os blocos do ndice secundrio) e teria mais um acesso para buscar o bloco do arquivo. Em uma pesquisa em arquivo ndice Multinvel, teramos: 1 nvel (Arquivo Original) 3.000 blocos (registros desordenados) 2 nvel (Arquivo ndice Secundrio) 30000/68 = 442 blocos 3 nvel (Arquivo ndice Principal) 442/68 = 7 blocos 4 nvel (Arquivo ndice Principal) 7/68 = 1 bloco Teramos 4 nveis e, portanto, 4 acessos
103
Cinthia C L Caliari
Arquivo original
Chave Outros campos
:
4624
10 19 4
:
1 6 50 5
:
68 4692 4760 4828 4896 4964 69 70 71 72 73
:
35
:
9316
:
136
21 7 48
:
Figura 6: Exemplo de ndice Multinvel.
104
Cinthia C L Caliari
Bibliografia: ELMASRI, Ramez, NAVATHE, Sahmkant B..Sistemas de Banco de Dados Fundamentos e Aplicaes. Traduo: Tereza C. P. de Souza. Rio de Janeiro: LTC Livros Tcnicos e Cientficos, 2002. 837 pg. GARCIA-MOLINA, Hector, ULLMAN, Jeffrey D., WIDOM, Jennifer. Implementao de Sistemas de Banco de Dados. Traduo: Vandenberg D. de Souza. Rio de Janeiro: Campus, 2001. 685 pg. FERRAZ, Inhama Neves. Programao com Arquivos. Barueri, SP: Manole, 2003. 443 pg. Referncias Bibliogrficas: ELMASRI, Ramez, NAVATHE, Sahmkant B..Sistemas de Banco de Dados Fundamentos e Aplicaes. Traduo: Tereza C. P. de Souza. Rio de Janeiro: LTC Livros Tcnicos e Cientficos, 2002. 837 pg. GARCIA-MOLINA, Hector, ULLMAN, Jeffrey D., WIDOM, Jennifer. Implementao de Sistemas de Banco de Dados. Traduo: Vandenberg D. de Souza. Rio de Janeiro: Campus, 2001. 685 pg.
105
Cinthia C L Caliari
IV.6 RVORES B
So rvores de pesquisa balanceadas especialmente projetadas para a pesquisa de informao em discos magnticos e outros meios de armazenamento secundrio. Minimizam o nmero de operaes de movimentao de dados (escrita/leitura) numa pesquisa ou alterao. O grau de um n pode ser alto. Podem ser consideradas como uma generalizao natural das rvores de pesquisa binrias. DEFINIO: O nmero mximo de ponteiros que podem ser armazenados em um n a ordem da rvore, ou seja, a quantidade de filhos de um n. Uma rvore-B de ordem m uma rvore que satisfaz s seguintes condies: 1. Cada n possui m ou menos sub-rvores (descendentes, filhos). No mximo m. 2. Todo n, exceto a raiz, possui [m/2] ou m sub-rvores. No mnimo [m/2] ais [m/2] => menor inteiro maior ou igual a m/2 se m = 6 => mnimo 3. Se m = 5 => mnimo 3. No caso de ns filhos, estes possuem no mnimo (m/2)-1 componentes nos ns. 3. A raiz possui, no mnimo 2 sub-rvores no vazias, exceto no caso em que uma folha; 4. todas as folhas esto no mesmo nvel e todas as suas sub-rvores so vazias; 5. um n com k sub-rvores armazena k-1 chaves ou registros; 6. todos ns de derivao (aqueles que no so folhas) possuem exclusivamente subrvores no vazias. 7. As chaves esto em ordem crescente.
Exemplo: rvore de ordem m=4. Cada n possui no mnimo 2 subrvores e no mximo 4, com exceo da raiz e folhas. Cada n folha possui no mnimo (m/2)-1 elementos.
106
Cinthia C L Caliari
25
10 20
30 40
...
2 5 13 14 22 24
Exemplo dado em sala: Inserir os elementos em uma rvore B vazia, com m=5: 20, 40, 10, 30, 15, 35, 7, 26, 18, 22, 5, 42, 13, 46, 27, 8, 32, 38, 24, 45, 25. Neste caso cada n armazenar 4 chaves e 5 apontadores. Cada n ter no mnimo 2 chaves (com exceo da raiz). Cada n no folha ter no mnimo 3 subrvores.
107
Cinthia C L Caliari
2) Inserir 15: O nmero 15 deveria ser inserido entre o 10 e o 20 mas no h espao no n. Este n ser ento quebrado em 2 gerando uma rvore com uma raiz e duas subrvores. A pergunta : quem ser a raiz? Ser o elemento central de: 10 15 20 30 40, neste caso o 20.
_ 20 _ __ _ __ _ __ _ _ 10 _ 15 _ __ _ __ _ _ 30 _ 40 _ __ _ __ _
4) Inserir 22: O 22 deveria ser inserido antes do 26 mas no existe espao no n. Este n ser quebrado em 2, gerando outro n O o. elemento que subir para a raiz ser o nmero central entre: 22 26 30 35 40, neste caso o 30:
_ 20 _ 30 _ __ _ __ _ _ 7 _ 10 _ 15 _ 18 _ _ 22 _ 26 _ __ _ __ _ _ 35 _ 40 _ __ _ __ _
108
Cinthia C L Caliari
7) Inserir 32:
_ 10 _ 20 _ 30 _ 40 _ _ 5 _ 7 _ 8 _ __ _ _ 13 _ 15 _ 18 _ __ _ _ 22 _ 26 _ 27 _ __ _ _ 32 _ 35 _ __ _ __ _ _ 42 _ 46 _ __ _ __ _
9) Inserir 25: Para inserir o 25 o n dever ser quebrado. O elemento central que dever subir ser: 22 24 25 26 27, o prprio 25. Para inserir o 25 no n superior no existe espao, ou seja, este n dever ser quebrado tambm para inserir o 25. O elemento que dever subir: 10 20 25 30 40, ser novamente o 25. Ento teremos:
_ 25 _ __ _ __ _ __ _
_ 10 _ 20 _ __ _ __ _
_ 30 _ 40 _ __ _ __ _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 27 _
_ 32 _ 35 _ 38 _ __ _
_ 42 _ 45 _ 46 _ __ _
109
Cinthia C L Caliari
Exerccio: Insira os elementos abaixo em uma rvore B vazia de m=5: 20, 10, 40, 50, 30, 55, 3, 11, 4, 28, 36, 33, 52, 17, 25, 13, 45, 9, 43, 8, 48. O processo de remoo um pouco mais complexo que o de insero: o Remover um elemento de um n folha com quantidade de elementos > (m/2)-1 fcil, basta eliminar o elemento mantendo o n ordenado.
_ 25 _ __ _ __ _ __ _
Remover o 46 fcil!
_ 10 _ 20 _ 30 _ 40 _
_ 30 _ 40 _ 30 _ __ _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 27 _
_ 32 _ 35 _ 38 _ __ _
_ 42 _ 45 _ 46 _ __ _
o Remover um elemento de um n folha com quantidade de elementos = (m/2)-1, envolve alguns passos.
_ 25 _ __ _ __ _ __ _
_ 10 _ 20 _ __ _ __ _
_ 30 _ 40 _ __ _ __ _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 27 _
_ 32 _ 35 _ 38 _ __ _
_ 42 _ 45 _
_ __ _
110
Cinthia C L Caliari
r.1) O n da direita ou n da esquerda possui um nmero de elementos maior que (m/2)-1. Neste caso se redistribui os elementos pertencentes raiz do n onde ocorrer a remoo (n esquerdo e direito da raiz). Neste caso vamos eliminar o 27, deveremos redistribuir: 26 30 32 35 38. O 32 o elemento central, ser a nova raiz:
_ 25 _ __ _ __ _ __ _
_ 10 _ 20 _ __ _ __ _
_ 32 _ 40 _ __ _ __ _
_ 5 _ 7 _ 8 _
_ 00 _ 13 _ 15 _ 18 _
_ 0 _ 22 _ 24 _
_ 00 _ 26 _ 30 _
_ 35 _ 38 _
_ __ _ 0 _ 42 _ 45 _
_ __ _
r.2) Uma outra situao quando o n da direita ou da esquerda no possui um nmero maior que (m/2)-1 ou a redistribuio causar em uma rvore no B. Neste caso haver uma juno dos ns. Um exemplo a eliminao do 30. Neste caso o n da direita possui 2 elementos, e assim no poderemos tirar um visto que a quantidade ficar menor que 2. A soluo ento juntar os dois ns mais o elemento da raiz Ficaria com um n contendo 26 32 35 38. .
_ 25 _ __ _ __ _ __ _
_ 10 _ 20 _ __ _ __ _
_ 40 _
_ __ _ __ _
_ 5 _ 7 _ 8 _
_ 00 _ 13 _ 15 _ 18 _
_ 0 _ 22 _ 24 _
_ 00 _ 26 _ 32 _ 35 _ 38 _
_ 42 _ 45 _
_ __ _
111
Cinthia C L Caliari
Caso a juno mantenha as restries da rvore B, tudo bem. Caso no mantenha, como a situao acima, o processo deve ser propagado para o n superior, ou seja, os ns do 2 nvel sero concatenados mais a raiz.
_ 10 _ 20 _ 25 _ 40 _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 32 _ 35 _ 38 _
_ 42 _ 45 _
_ __ _
o Remover um elemento da raiz da rvore: caso a raiz seja nica, basta remove-lo. Caso a raiz tenha filhos deveremos substituir a raiz pelo elemento mais a esquerda da direita ou mais a direita da esquerda. Se o n folha onde foi removido o elemento cair em um dos casos citados acima, s aplicar uma das tcnicas mencionadas. Na remoo do 25, troca-se pelo mais a esquerda da direita: Antes:
_ 25 _ __ _ __ _ __ _
_ 10 _ 20 _ 30 _ 40 _
_ 32 _ 40 _ __ _ __ _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 30 _
_ 35 _ 38 _
_ __ _
_ 42 _ 45 _
_ __ _
Depois:
_ 26 _ __ _ __ _ __ _
_ 10 _ 20 _ __ _ __ _
_ 32 _ 40 _ __ _ __ _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 30 _
_ 35 _ 38 _
_ __ _
_ 42 _ 45 _
_ __ _
112
Cinthia C L Caliari
Neste caso a rvore deixou de ser B, e ento caio na situao de n folha. Como no o n da direita no pode ceder elementos, haver uma juno: 30 32 35 38, que deixar a rvore fora da definio tambm e ento deverei juntar o ns do nvel intermedirio.
_ 10 _ 20 _ 26 _ 40 _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 30 _ 32 _ 35 _ 38 _
_ 42 _ 45 _
o Remover um elemento de um n intermedirio (no raiz e nem folha). Na remoo do 10, por exemplo, pegaria o elemento mais a direita da esquerda ou o elemento mais a esquerda da direita. Neste caso vou pegar o elemento mais a direita da esquerda.
_ 25 _ __ _ __ _ __ _
_ 10 _ 20 _ 30 _ 40 _
_ 32 _ 40 _ 30 _ 40 _
_ 5 _ 7 _ 8 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 30 _
_ 35 _ 38 _
_ 46 _
_ 42 _ 45 _
_ __ _
_ 25 _ __ _ __ _ __ _
_ 8 _ 20 _ __ _ __ _
_ 32 _ 40 _ __ _ __ _
_ 5 _ 7 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 30 _
_ 35 _ 38 _
_ __ _
_ 42 _ 45 _
_ 46__ _
113
Cinthia C L Caliari
Vamos supor agora que desejo remover o 32. Pego o elemento mais a direita da esquerda:
_ 25 _ __ _ __ _ __ _
_ 8 _ 20 _ __ _ __ _
_ 30 _ 40 _ __ _ __ _
_ 5 _ 7 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _
_ 35 _ 38 _
_ __ _
_ 42 _ 45 _
_ __ _
Minha rvore deixa de ser B, e cai em um dos casos de n folha: o Primeiro vou juntar, pois o n a direita possui uma quantidade menor que (m/2)-1.
_ 25 _ __ _ __ _ __ _
_ 8 _ 20 _ __ _ __ _
_ 40 _
_ __ _ __ _
_ 5 _ 7 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 30 _ 35 _ 38 _
_ 42 _ 45 _
_ __ _
_ 5 _ 7 _
_ 13 _ 15 _ 18 _
_ 22 _ 24 _
_ 26 _ 30 _ 35 _ 38 _
_ 42 _ 45 _
_ __ _
114
PESQUISA E ORDENAO
Resumindo remoo: N folha Caso simples: apenas remover a inda fica uma rvore B. Caso complexo 1: o n vizinho possui uma quantidade maior que (m/2)-1 elementos: s redistribui. Caso complexo 2: o n vizinho no possui exatamente (m/2)-1 elementos: o Juntar o n do elemento removido mais o n vizinho mais a raiz. o Se a rvore deixou de ser B, junto os ns superiores (ns superiores + raiz caso 2) ou redistribuo (caso 1). N Substituo o elemento pela chave mais a direita da esquerda ou pela intermedirio chave mais a esquerda da direita. ou raiz Se a rvore deixar de ser B, resolvo com uma das solues de N folha.
IV.7 RVORES B+
rvore B+ so semelhantes s rvores B com exceo do nvel onde esto as folhas. O nvel onde esto as folhas composto por uma lista encadeada. O ns intermedirios armazenam apenas o campo de pesquisa, os apontadores para os blocos onde esto as informaes completas ficam nas folhas. Esta rvore indicada quando o item de maior impacto for a pesquisa, ou seja, quando ocorre pouca insero ou remoo. A facilidade desta rvore sobre a rvore B diz respeito necessidade de exibir o arquivo ordenado. Neste caso a rvore no precisa ser percorrida, apenas a lista de ns folha. As rvores B+ tambm facilitam o acesso concorrente ao arquivo. Como no h necessidade de usar apontadores nos ns folha, possvel utilizar este espao para armazenar uma quantidade maior de registros em cada n folha. Exemplo de uma rvore B:
_ 20 _ 30 _ __ _ __ _ _ 7 _ 10 _ 15 _ 18 _ _ 20 _ 22 _ 26 _ __ _ _ 30 _ 35 _ 40 _ __ _
A operao de insero de um registro em uma RVORE B+ semelhante de uma rvore B. A nica diferena que quando uma folha dividida em duas, o algoritmo faz uma cpia da chave que pertence ao registro do meio para a pgina pai no nvel anterior, retendo o registro do meio no n folha da direita. 115
PESQUISA E ORDENAO
A remoo mais simples, pois o registro a ser retirado est sempre no n folha, mesmo que uma cpia da chave do registro a ser retirado esteja no ndice.
27
38
72
85
96
3 12
30
34
40 43 47
60
70
77
83
88
90
99 102
4) Explicar como procurar a menor chave de uma rvore B. 5) Inserir os dados abaixo em uma rvore B, inicialmente vazia, de ordem 4: 0, 10, 20, 30, 1, 11, 21, 31, 2, 12, 22, 32, 4, 14, 24, 34, 5, 15, 25, 35, 6, 16, 26, 36, 7, 17, 27, 37, 8, 18, 28, 38, 9, 19, 29, 39. 7) Remover da rvore anterior, todos os mltiplos de 3. 8) Qual a diferena entre uma rvore B e uma rvore B+?
116
PESQUISA E ORDENAO
29
1 5
9 18 19 22
29 33
50 52
60 65 70
75
80
15 30 36 48 71
5 10
18 24 29
32 34 35
38 39
42 45
56 65
72 80
81
a) Quais as possveis ordens que esta rvore pode ter? b) Supondo que ela tenha ordem 5, retire o registro de chave 48. c) Insira os registros de chave 19, 20, 31 e 33 nesta ordem. 11) Dadas as rvores abaixo, ambas de ordem 5, identifique qual delas B e qual B+, justificando, retire o elemento 20 da rvore B e coloque o elemento 82 na rvore B+, nesta ordem.
15 32 6 10 18 25 40 56
2 3 5
7 9
12 14
16 17
19 20
26 31
35 37
41 46 51 58 61 65 72
20 40 10 15 25 32
55
71
2 3 5
10 13
17 19
20 22 23 27 28 29 30
32 35 37
49
52
56 58 65
72 75 80 81
117
PESQUISA E ORDENAO
12) Suponha um arquivo com 100.000 registros no-spanned, onde cada registro ocupa 420 bytes. Sabemos que o armazenamento em memria secundria seja feito atravs de blocos. No nosso caso, cada bloco comporta 4 Kbytes. Se fosse utilizado um arquivo de ndices, cada registro (chave + endereo) ocuparia 36 bytes. Com base nesses dados, calcule quantos acessos a disco cada pesquisa abaixo faria: a) Pesquisa direto no arquivo original se ele estiver desordenado b) Pesquisa direto no arquivo original se ele estiver ordenado c) Pesquisa no arquivo de ndice principal d) Pesquisa no arquivo de ndice secundrio e) Pesquisa usando o mtodo multi-nvel e tomando como base o arquivo original desordenado f) Pesquisa usando o mtodo multi-nvel e tomando como base o arquivo original ordenado
13) Suponha um arquivo com 25.000 registros no-spanned, organizado de forma no ordenada, onde cada registro ocupa 120 bytes. Sabemos que o armazenamento em memria secundria feito atravs de blocos. No nosso caso, cada bloco comporta 1024 bytes. Responda: a) Quantos registros haver por bloco? b) Quantos blocos este arquivo utiliza? c) Se fosse feita uma pesquisa seqencial no arquivo, quantos acessos, em mdia, seriam necessrios? Supondo que fosse feito um arquivo de ndices multi-nvel, onde cada registro, chave + ponteiro, utilizasse 15 bytes, responda: d) Quantos registros haver por bloco, em cada nvel? e) Quantos blocos so utilizados em cada nvel? f) Se fosse feita uma pesquisa, quantos acessos seriam necessrios para acessar o elemento pesquisado?
14) Suponha um arquivo com 70.000 registros no-spanned, organizado de forma no ordenada, onde cada registro ocupa 120 bytes. Sabemos que o armazenamento em memria secundria feito atravs de blocos. No nosso caso, cada bloco comporta 2 Kbytes. Responda: a) Quantos registros haver por bloco? b) Quantos blocos este arquivo utiliza? c) Se fosse feita uma pesquisa seqencial no arquivo, quantos acessos, em mdia, seriam necessrios? Supondo que fosse feito um arquivo de ndices multi-nvel, onde cada registro, chave + ponteiro, utilizasse 10 bytes, responda: d) Quantos registros haver por bloco, em cada nvel? e) Quantos blocos so utilizados em cada nvel? f) Se fosse feita uma pesquisa, quantos acessos seriam necessrios para acessar o elemento pesquisado?
118