UNIVERSIDADE COMUNITÁRIA DA REGIÃO DE CHAPECÓ ACEA CURSO DE CIÊNCIA DA COMPUTAÇÃOEstrutura de Arquivos José Carlos Toniazzo Chapecó, 20010/1 Índice Índice....................................................................................................................................................2 1.Mídias de armazenamento secundário ..............................................................................................3 1.1. Introdução.................................................................................................................................3 1.2. Fitas Magnéticas .......................................................................................................................4 1.3. Discos Magnéticos....................................................................................................................8 1.4. Jornada de um Byte ................................................................................................................16 2. Organização de Arquivos ...............................................................................................................19 2.1. Introdução...............................................................................................................................19 2.2. Terminologia ..........................................................................................................................19 2.3. Introdução aos Arquivos Seqüenciais.....................................................................................20 2.4. Introdução aos Arquivos Seqüenciais Indexados ...................................................................21 2.5. Introdução aos Arquivos Indexados .......................................................................................23 2.6. Introdução aos Arquivos Diretos............................................................................................24 2.7. Introdução aos Arquivos Invertidos .......................................................................................25 2.8. Quadro Comparativo entre as Organização de Arquivos .......................................................26 2.9. Exercícios ...............................................................................................................................26 3. Arquivos em C ...............................................................................................................................27 3.1. Abrindo e fechando um arquivo .............................................................................................27 3.2. Lendo e escrevendo caracteres em arquivos...........................................................................29 3.3. Outros comandos de acesso a arquivos ..................................................................................31 3.4. Fluxos padrão .........................................................................................................................36 4. Compressão de Dados...............................................................................................................37 4.1. Introdução...............................................................................................................................37 4.2. Tipos de Compressão .............................................................................................................38 4.3. Compressão Orientada a Caracter ..........................................................................................38 4.4. Compressão Estatística ...........................................................................................................44 5. Algoritmos para classificação externa ......................................................................................50 5.1. Método da seleção ..................................................................................................................50 5.2. Ler o arquivo e colocar na memória a tabela de chaves.........................................................52 5.3. Mergesort de arquivos ............................................................................................................53 5.4. Arquivos dinâmicos................................................................................................................55 6. Métodos de Pesquisa.................................................................................................................55 6.1. Pesquisa Sequencial................................................................................................................55 6.2. Pesquisa Binária .....................................................................................................................56 6.3. Hashing...................................................................................................................................56 7. Algoritmos para indexação .......................................................................................................65 7.1. Índice Invertido.......................................................................................................................65 7.2. Arquivos de Assinatura ..........................................................................................................67 7.3. Algoritmos de Ranking...........................................................................................................69 Referências .........................................................................................................................................75 1.Mídias de armazenamento secundário 1.1. Introdução Nos últimos 20 anos, a capacidade de armazenamento on-line aumentou em cerca de três vezes em relação da potência em CPU. Contudo, a memória representa talvez a área de maior limitação no desenvolvimento de sistemas de computação mais avançados. A memória interna fornece os requisitos de armazenamento da(s) unidade(s) central (ais) de processamento para a execução de programas, incluindo programas de aplicação e programas de sistemas como montadores, carregadores, editores de ligação, compiladores, rotinas utilitárias e rotinas supervisoras do sistema operacional. A capacidade de armazenamento da memória interna é limitada pelo custo das unidades da memória interna. Os requisitos de armazenamento para os programas e dados sobre os quais eles operam geralmente excedem a capacidade da memória interna da maioria dos sistemas de computação. Assim, há a necessidade de se ter outros recursos de armazenamento para armazenar programas e dados. Qualquer pessoa que crie programas para armazenamento e/ou dados deve ser capaz de selecionar (se o programador tiver oportunidade de selecionar) os meios adequados nos quais armazenar os arquivos e deve também estar atento para a adequação dos mecanismos de armazenamento às organizações de arquivo utilizadas. Por exemplo, as fitas magnéticas permitem apenas um acesso seqüencial aos dados, enquanto que discos, tambores e memórias magnéticas são dispositivos de armazenamento que permitem o acesso aleatório. Com meios de acesso seqüencial, somente o próximo registro ou registro anterior pode ser localizado facilmente; esse tipo de meio é recomendado quando ler e gravar o próximo registro é o tipo mais comum de operação. Com os meios de acesso aleatório, um comando de hardware é usado para posicionar o mecanismo de acesso a cada parte do meio de armazenamento que pode ser endereçado. Mecanismos de acesso aleatório são excelentes para a localização de um registro de dado que tenha endereço conhecido. Quando os programadores de sistemas selecionam mecanismos externos de armazenamento para armazenar arquivos de dados e arquivos de programas, há vários itens que devem ser levados em consideração: 1. Capacidade. O total de dados que pode ser armazenado no meio de armazenamento. 2. Portabilidade. Fitas magnéticas e alguns discos são removíveis, permitindo o armazenamento off-line de arquivos. 3. Custo relativo. O custo de um mecanismo aumenta proporcionalmente com a velocidade e conveniência de acesso aos registros. 4. Tamanho do registro. O tamanho de um conjunto de dados contínuos que podem ser endereçados num mecanismo. 5. Método de acesso. O acesso direto (aleatório) a qualquer registro num mecanismo pode ser possível, ou então o equipamento pode restringir somente ao acesso seqüencial. 6. Velocidade de transferência de dados. A velocidade, geralmente em bits, ou caracteres por segundo, na qual os dados podem ser transferidos entre a memória interna e o mecanismo. 7. Tempo de posicionamento. Os mecanismos de discos e de tambor com cabeças de leitura/gravação móveis geralmente devem preceder cada operação de ler/gravar com uma procura que fisicamente consiste em mover a cabeça de leitura/gravação sobre a trilha que contém o registro desejado. 8. Latência. Depois de um comando de ler/gravar ser aceito pelo mecanismo, normalmente este leva algum tempo adicional, o tempo de espera (ou tempo de retardo rotacional), antes que o inicio do registro a ser acessado esteja sob a cabeça de leitura/gravação e que a transferência de dados possa começar; é o tempo de partida para a fita magnética alcançar a sua velocidade de operação a partir da posição “parada” ou o tempo de retardo rotacional dos discos e tambores rotativos. A capacidade de armazenamento e o tempo de acesso de cada tecnologia de armazenamento são apresentadas. 3. O programador pode desejar saber se o arquivo caberá ou não num único volume. Os cálculos de espaço são importantes por duas razões: 1. São baratas se comparadas a outros meios de armazenamento. são dadas equações para cálculo do espaço de armazenamento ocupado por um arquivo e o total de tempo necessário para se acessar um bloco de registros lógicos. O tempo é importante porque um programador pode ter limitações de tempo de acesso para a recuperação de dados que devem ser considerados ao escolher um armazenamento externo no qual armazenar um arquivo. Um certo número de pistas corre ao longo da fita. Capacidade. velocidade de transferência de dados e custo por bit são as características básicas de desempenho dos mecanismos de armazenamento. A aparência física da fita magnética é similar à das fitas usadas em gravadores. a menos que todos os volumes estejam disponíveis on-line. os volumes podem ter que ser montados e desmontados diversas vezes durante o processamento do arquivo. Fitas Magnéticas A fita magnética foi o primeiro meio externo de armazenamento a ser largamente usado e continua a ser um dos meios mais comuns de armazenamento para dados que podem ser processados de forma seqüencial. As fitas magnéticas são importantes meios externos de armazenamento pelas razões seguintes: 1.2. 1. Um arquivo que possa – ou deva – ser acessado por diversos usuários simultaneamente deve ser armazenado num equipamento que permita o compartilhamento. Os mecanismos de armazenamento com acesso seqüencial não são apropriados para esse tipo de compartilhamento. . Considerações de tempo para dispositivos de armazenamento externo são normalmente mais importantes para um programador do que considerações de espaço. Em algumas situações não é desejável expandir o arquivo em mais de um volume. tempo de acesso (quanto tempo leva para se ler os dados num dispositivo). Algumas das propriedades mencionadas acima não são características de todos os mecanismos de armazenamento discutidos neste capítulo. tal como o disco magnético. Quando uma tecnologia de armazenamento está sendo avaliada. 2.Outra propriedade dos mecanismos externos de armazenamento que pode ser importante para algumas aplicações é a capacidade do equipamento poder ser compartilhado simultaneamente por dois ou mais usuários. São compactas e portáteis. caractere por caractere. não há tempo de procura para os discos e tambores de cabeças fixas e grandes memórias magnéticas. Outra razão importante para apresentar e estudar cálculos de tempo e espaço é que isso fortalece a compreensão da operação dos equipamentos. O programador pode ter que especificar explicitamente o total de espaço de armazenamento requerido por um arquivo quando ele for criado. Os dados são codificados na fita. Além disso. Quanto maior a densidade da área. 2. Devido ao baixo custo. A fita é feita de material plástico coberto com uma substância magnetizável. são ideais para uso em armazenamento de reserva off-line e para arquivamento de arquivos. Por exemplo. o que facilita o armazenamento off-line. menor o custo por bit e . discos e tambores fixos e removíveis. a densidade da área (em bits por polegada quadrada) é o número chave a ser considerado.da mesma forma – menor o tempo médio de acesso para qualquer capacidade dada. com uma pista para cada posição de bit na representação codificada de um caractere. do contrário. Os meios e equipamentos de armazenamentos discutidos neste capítulo são fitas magnéticas. O bit da pista 1 é o bit da paridade. A fita da Figura 1 é escrita na paridade par. O caractere da paridade longitudinal. O caractere de verificação por redundância é gravado no final da fita. As fitas podem ter de 7 ou 9 pistas. Os dados são gravados na fita de 7 pistas na forma binária ou na codificação BCD. chamado de caractere de verificação por redundância. Os dados podem ser gravados com paridade par ou ímpar. da pista 2 à 9. O motivo pelo qual o registro é lido diversas vezes é que as fitas são vulneráveis à poeira e outras substâncias estranhas a ela e por isso pode acontecer que a unidade de fita não funcione adequadamente. E cada caractere é representado na fita pela seqüência de conjunto de bits de 0 ou 1. o bit de paridade é gravado igual a 1 quando o número de bits 1. Se o número de bits “1” da pista for par. o que será verificado por uma nova leitura. Quando a fita é gravado na paridade ímpar. Paridade Além das pistas que registram os dados. Quando tanto a paridade vertical quanto a longitudinal são usadas.1. 3. A fita de 7 pistas é similar à de 9. é menos provável que um erro escape da detecção. Cada pista é examinada longitudinalmente e o número de bits 1 da pista é contado. o número de bits 1 da pista 2 à pista 9 é par. Figura 1. então “1” é gravado no caractere de verificação por redundância na posição correspondente ao número da pista. exceto com o bit da pista 1 é gravado “1” de forma a indicar que o número de bits 1. é gravado na pista 1 pela unidade de fita á medida que os dados são gravados na fita. a unidade de fita controla o número de bits 1 nas pistas de 1 a 9 para certificar-se de que este número está em conformidade com a paridade da fita. A fita 9 pistas é mais usada do que a de 7.Porção da fita de 9 pistas O bit de paridade serve como controle de exatidão dos dados gravados quando eles forem lidos da fita. há uma pista adicional que registra o bit de paridade usado para o processamento de erro. 4. Algumas fitas têm um caractere de paridade longitudinal gerado quando os dados são gravados na fita. 2. Os dados são gravados na fita de 9 pistas tanto na forma binária como a codificação EBCDIC. A paridade acima descrita é às vezes chamada apenas de paridade simples ou paridade vertical. Quando uma fita é lida.1. . é ímpar. é gerado da seguinte maneira: 1. da pista 1 à 9. Se não estiver ocorre a interrupção de erro da paridade. então “0” é gravado no caractere de verificação por redundância. Assim. nas pistas 2 a 9. por isso o bit 1 é gravado na pista 1. em alguns casos um erro de paridade pode ocorrer mesmo que o registro esteja gravado corretamente. A rotina de interrupção faz então com que o registro em que ocorreu o erro de paridade seja relido diversas vezes pela unidade de fita até que o registro seja lido sem erro de paridade ou que as tentativas de leitura tenham alcançado um limite determinado pelo sistema. for ímpar. exceto que os caracteres são gravados verticalmente da pista 2 a 7. Se o número de bits “1” da pista for ímpar.2. A paridade ímpar é similar. A Figura 1 ilustra uma seção de fita de 9 pistas. O bit de paridade é gravado também na pista 1. Cálculo de espaço e Tempo para Fita Magnética A quantidade de dados que podem ser armazenados numa fita magnética depende do tamanho dos blocos e da densidade em que eles podem ser registrados na fita. Além disso. E será preciso algum tempo para que a fita alcance a velocidade ideal no próximo comando. contudo. 1.3. digamos um ou dois milhões. e permita que ela chegue à velocidade requerida para ler ou gravar sem distorção.Formato da fita magnética Registros físicos consecutivos são separados por um separados de registros (IRG). Ao término de um comando de ler ou gravar. . Daí o tamanho do blocos ser determinado. Quando a fita é colocada na unidade. as memórias intermediárias não podem ser arbitrariamente grandes. uma ou mais memórias intermediárias. Por outro lado. é posicionada de forma a que o ponto de carga esteja pronto para um comando de Entrada/Saída.1. Existe um ponto de equilíbrio entre a capacidade de armazenamento da fita e o tempo de leitura/gravação. pela quantidade da memória interna disponível para a memória intermediária. para números menores de caracteres. suficientemente grandes para receber um bloco. parte do separador de registros passa pela cabeça de leitura/gravação. Figura 2. Nenhum dado é registrado no separador de registros. resultando num alto fator de bloco. já que a memória interna é geralmente algo de difícil obtenção. devem existir na memória interna.2. o movimento da fita prossegue sem interrupção. Separação entre registros Os dados são escritos (lidos) na (da) fita por uma unidade de fita à medida que a fita passa pelo dispositivo da cabeça de leitura/gravação. em certa medida.75 polegadas de comprimento nas fitas de 7 pistas e 0. que permite uma fita iniciar e parar entre comando individuais de ler ou gravar. O efeito negativo do separador de registro é diminuir o volume de dados que podem ser armazenados numa fita. Algumas unidades de fita possuem uma alta velocidade para rebobinamento. O separador de registros tem normalmente 0. a fita pára.2. 1. que se aplica apenas quando o número de caracteres a ser rebobinado é maior que determinado valor. Grandes blocos. Se a operação seguinte na mesma fita for iniciada durante este tempo. fazem com que a fita seja mais usada para armazenar dados e menos utilizadas pelo separador de registros. As fitas magnéticas podem ser rebobinadas ao ponto de carga por um comando de rebobinar. o rebobinamento é feito na velocidade normal de leitura/gravação.2. o tempo médio para ler/gravar um registro físico é inversamente proporcional ao fator de bloco já que menos separadores de registros devem ser utilizados. Os dados gravados nas fitas magnéticas o são no formato ilustrado na Figura 2.2.4.6 nas fitas de 9 pistas. Para utilizar de forma eficiente o armazenamento em fita e para minimizar o tempo de leitura/gravação. Contudo. A principal função de um separador de registros é criar espaço suficiente que permita à fita parar após o comando Entrada/Saída. de um lado. o fator de bloco deve ser relativamente grande. e a quantidade de memória interna disponível para as memórias intermediárias. Rebobinamento da fita Uma fita normalmente tem um ponto de carga indicando o ponto de partida da fita a partir do qual os dados podem ser gravados. Uma unidade de fita é projetada para ler ou gravar apenas quando a fita magnética está se movendo a uma determinada velocidade. se a operação seguinte não ocorrer logo. 1600 cpi e 6250 cpi.25M bytes/seg 470K bytes/seg Transferência Cálculos de espaço O espaço ocupado por um bloco depende do: 1. DEN=800 cpi e IRG=0.9 polegadas = 375 pés = 114.3 metros . tanto para espaço quanto para tempo. de algumas unidades de fita disponíveis no mercado. 800 cpi. bytes por polegada ( bpi) ou em caracteres por polegada (cpi).A densidade da fita é expressa em bits por polegada (bpi). Fabricante Modelo Velocidade Densidade CDC 626 75 pol/seg 800 carac/pol Univac Uniservo 12 42.75 polegadas é ST = 10000/3 x (0. BF= 3. A Tabela 1 dá as características. A Tabela 2 contém uma lista de símbolos usados nas equações apresentadas abaixo.000. inclusive a densidade. As densidade mais comuns de gravação de fitas magnéticas são 556 cpi. 2. Comprimento do registro lógico. Fator de bloco.75 pol + (3 x 160 caracteres) / 800 cpi ) ST = 4500.7 pol/seg CDC 679-7 200 pol/seg IBM 3420-4 75 pol/seg 6250 bytes/pol Telex 6420-66 125 pol/seg 6250 bytes/pol 780K bytes/seg 1600 carac/pol 6250 bytes/pol Velocidade de 120K carac/seg 68K carac/seg 1. LRL=160 caracteres. 3. Símbolo NL BF IRG DEN SPD LRL ST TT TA Fator de bloco Separador de registros (em polegadas) Densidade (cpi ou bpi) Velocidade (polegadas por segundo) Comprimento do registro lógico (caracteres) Espaço total (polegadas) Tempo total (segundos) Descrição Número de registros lógicos de um arquivo Tempo de início/parada ou tempo para passar sobre o IR (milissegundos) O espaço total (ST) necessário para um arquivo de registros lógicos (NL) é dado pela equação ST = NL/BF x (IRG + (BF x LRL)/DEN ) O valor entre parênteses em é o espaço ocupado por um único bloco. Densidade da fita. O espaço total necessário para um arquivo seqüencial com NL = 10. 2. são um meio relativamente barato.75 polegadas. Os limites da tecnologia estavam muito acima da demanda. Em comparação com a fita magnética. Tendo-se SPD=75 polegadas/segundo. Discos Magnéticos Os discos magnéticos são dispositivos de armazenamento de acesso direto tanto para armazenamento de dados on-line como off-line. continuam sendo adequados para o armazenamento de grandes arquivos. assim. 3. 1. Um tempo de ler o bloco em si. O produto de SPD x DEN é a velocidade de transferência de dados. Meios de armazenamento de baixo custo em superfícies magnéticas homogêneas. 1. BF=3. O tempo total para leitura de um arquivo de registro NL.000 caracteres por segundo.68 seg Os requisitos de espaço e acesso para um arquivo em fita magnética (e para a maioria dos demais meios de armazenamento) diminuem à medida que aumenta o fator de bloco.6 mseg (o valor de TA é o tempo de partida/parada e não o tempo de mobilidade).0126seg + (3 x 160 caracteres) / (75 pol/seg x 800cpi) ) TT = 68. Vantagens e Desvantagens de Fita Magnética Uma limitação da fita magnética é que os registros não podem ser acessados aleatoriamente. Um tempo para ultrapassar um separador de registro. O espetacular sucesso do disco magnético advém de certas características inerentes desta tecnologia: 1. o tempo de leitura de um arquivo de 10. oferece tempo de acesso relativamente menor e alta velocidade para transferência de dados.2. se partirmos do princípio de que não há rebobinamento. Além disso. Os fabricantes de mecanismos de discos conseguiram aumentar a densidade de área dos meios de gravação em muitas vezes ao longo dos anos. portáteis e adequadas para o armazenamento off-line. permitindo assim muito espaço para crescimento e expansão da capacidade e desempenho dos mecanismos.Cálculos de Tempo O tempo para se ler um bloco consiste em: 1. .000 registros lógicos com uma parada total após cada leitura é TT = 10000/3 x (0.5. A velocidade de transferência de dados das unidades de fita mais comuns varia de cerca de 30. TA=12. os registros devem ser processados na ordem em que estão gravados na fita. ou seja. LRL=160 caracteres. As fitas magnéticas têm a vantagem de ser compactas.3.000 a aproximadamente 7500. DEN= 800 cpi e IRG= 0. é dado por TT = (NL/BF) x [ TA + {(BF x LRL) / (SPD x DEN)} ] A quantidade entre parênteses é o total de tempo necessário para se ultrapassar um separador de registro mais o tempo para a leitura do bloco. Acesso que permite que dezenas de milhões de bits compartilhem uma cabeça de leitura/gravação. Acessar um registro seqüencialmente significa ler todos os outros registros que o antecedem. 2. Há dois tipos de discos em uso: os discos fixos (também chamados de discos de cabeça fixa) e os discos removíveis (também chamados de discos de cabeça móvel).são capazes de armazenar a mesma quantidade de dados. já que podem ser facilmente danificadas. armazenado ou transportado. a razão para isso é que a densidade de gravação das trilhas mais internas é maior do que a densidade de gravação(bits por polegada) das mais externas. (ver Figura 4). Cada cabeça flutua acima ou abaixo da superfície (cerca de 0. Os dados são registrados nas trilhas pelas cabeças de leitura/gravação. dentre os dois tipos. Quando um comando READ( ) é formado para um byte em particular num arquivo em disco.1 Discos Fixos O disco fixo da Figura 3 consiste em seis pratos com material ferromagnético em sua superfície proporcionando o meio de armazenamento. As trilhas que estão diretamente em cima e abaixo uma da outra formam um cilindro. o SO do computador localiza a superfície.001 polegadas da superfície). porque facilitam o armazenamento de arquivos off-line e o custo/bit é menor. Cada trilha é dividida freqüentemente em setores que é a menor porção endereçável de um disco. Os discos removíveis são os mais comuns. chamados de trilhas. enquanto que os discos removíveis podem ser facilmente retirados de uma unidade de disco e substituído. Os discos em mecanismos de disco fixo não são removidos da unidade de disco (exceto para manutenção). Embora as trilhas variem de comprimento. O disco da Figura 3 tem dez trilhas por superfície. então procura o byte solicitado do buffer. reunidas num conjunto de cabeças de leitura/gravação que é fixo. todas elas – num determinado disco .3. . Figura 3. a trilha e o setor e lê o setor inteiro para uma área especial na RAM chamada buffer. Cada superfície é dividida em anéis concêntricos. uma para cada pista. enquanto o disco está rodando a uma velocidade alta e constante.Vista lateral de um disco com cabeça fixa com 10 superfícies de leitura/gravação por superfície As superfícies mais externas dos pratos de cima e de baixo às vezes não são usadas para armazenamento de dados. 1. e a Figura 4 mostra uma vista de cima de um disco de cabeça móvel.Vista de cima da superfície de um disco com 200 trilhas principais e três trilhas alternativas (trilhas 200. com 203 pistas1*. dentre os dois tipos de mecanismos usados. o tempo de acesso para um disco de cabeça fixa é baixo. então a unidade do conjunto de cabeças podem mover-se horizontalmente para 200 posições diferentes. Se o disco da Figura 5 tiver 200 pistas principais por superfície. Discos Removíveis Como mencionado acima. Em alguns sistema de discos de cabeça móvel. A Figura 5 mostra um corte lateral do disco de cabeça móvel. as cabeças de leitura/gravação não são rigidamente fixadas no conjunto de montagem de cabeças (como estão na Figura 5) e podem ser movidas para dentro e para fora da superfície independente uma da outra. .2. assim sendo. porque os discos são removíveis e o custo/bit do armazenamento é menor. Há apenas uma cabeça de leitura/gravação por superfície do disco.202) Já que um disco fixo tem uma cabeça de leitura/gravação para cada pista. uma grande superfície de gravação pode ser coberta com apenas algumas cabeças de leitura/gravação.3. o disco de cabeça móvel é o mais comum.201. Os discos de cabeça fixa são normalmente usados em sistemas dedicados a uma ou a poucas aplicações e quando os arquivos devem ficar on-line como necessidade de um pequeno tempo de acesso. Cada uma dessas posições identifica um cilindro.Figura 4. 1 * As trilha de 0 a 199 são as principais. As cabeças de leitura/gravação geralmente movem-se em conjunto e apenas uma cabeça pode transferir dados de cada vez. porque o tempo de posicionamento é zero. Já que o mecanismo do conjunto de cabeças se move. Um disco de cabeça fixa com a mesma área de gravação de um disco de cabeça móvel tem um custo/bit maior devido ao custo das muitas cabeças de leitura/gravação necessárias. As de 200 a 2002 são trilhas alternativas usadas para substituir trilhas danificadas e algumas das principais que estejam com defeito. não há necessidade de tempo de posicionamento de colocar a cabeça de leitura/gravação na pista adequada da superfície. o conjunto de cabeças de leitura/gravação deve ser movido para dentro e para fora a fim de permitir o acesso a todas as trilhas de cada superfície. um cilindro de dados é o total de dados acessível com um posicionamento da unidade de cabeças de leitura/gravação. Este movimento é usualmente a parte mais lenta no processo de leitura em um disco. O maior componente do tempo de acesso para um disco de cabeça fixa é o tempo de latência. O tempo necessário para mover as cabeças de leitura/gravação para o seguinte chama-se tempo de posicionamento. 1. 3. permitindo. Sendo assim.Figura 5.000 registros de tamnho fixo num disco com as seguintes características: • • • Número de bytes por setor = 512 Número de setores por trilha = 40 Número de trilhas por cilindro = 11 . uma trilha consiste de um grupo de setores e um setor consiste de um grupo de bytes. os pratos superior e o inferior possuem apenas uma superfície utilizada para leitura e gravação e os demais (internos) utilizam ambas superfícies.000 bytes e trilhões de bytes.Vista lateral de um disco de cabeça móvel com 10 superfícies Já que a unidade do conjunto de cabeças num disco de cabeça móvel move-se. ela pode ser retirada da superfície dos discos. é fácil calcular a capacidade de uma trilha. Exemplo: Suponde que podemos armazenar um arquivo com 20. Estimação da Capacidade de um Disco O diâmetro de um disco varia de 3 à 14 polegadas e sua capacidade de menos que 100. podemos usar estes relacionamentos para computar a quantidade de espaços em disco que um arquivo provavelmente utilizará. Em HD´s típicos.3. de um cilindro e do disco: Capacidade de trilha(CT) = Número de setores por trilha (NST) X Bytes por setor (BS) Capacidade de cilindro(CC) = Números de trilha por cilindro (NTC) X Capacidade de trilha(CT) Capacidade do disco (CD) = Número de cilindros (NC) X Capacidade do cilindro (CC) Se sabemos o número de bytes num arquivo. A quantidade de dados que pode ser mantidos numa trilha depende da densidade (bits/polegada) da trilha. Já que um cilindro consiste de um grupo de trilhas. 1. o número de trilhas por cilindro depende do números de pratos. assim. que os discos sejam facilmente removidos das unidades de disco e substituído por outro disco. ler uma série de setores que estão todos na mesma trilha. após a leitura de um setor perder-se-ia o inicio do setor seguinte enquanto o computador estava processando a informação já lida.000 = 22.3.000 = 10. Organização física dos setores. se os setores logicamente adjacentes foram colocados fisicamente adjacentes no disco. usando-se as fórmulas: NumCilindros= TamArq CC TamArq= NumReg x TamReg= 20.000 setores 2 Um cilindro pode conter: 40 x 11 = 440 setores Assim. o computador gasta uma certa quantidade de tempo para processa-los antes de aceitar mais dados.4. Não se pode. mas não é uma maneira muito boa de armazenar os setores fisicamente. um após o outro. Supondo que nosso disco tenha um fator de intercalação igual a 5. o número de cilindros necessários é aproximadamente: 10. geralmente. Organização de setores Existem duas maneiras básicas de organizar os dados num disco: por setores e por blocos definidos pelo usuário.7 225280 1. sendo que cada registro necessita de 256 bytes? Já que cada setor mantém 2 registros. após a leitura dos dados. só se consegue ler um setor em cada rotação do disco.Quantos cilindros são necessários pra armazenar o arquivo. Há diversas visões que se pode ter da organização de setores numa trilha.000 x 256= 5120000 CC= NTC x NST x BS = 11 x 40 x 512 = 225280 NumCilindros= 5120000 = 22. o arquivo necessita: _ 20. esta é uma maneira perfeitamente adequada de ver um arquivo logicamente. ao passo que na organização anterior (Figura 6 a) seria necessário 32 rotações. isto é. Se observarmos esta figura podemos ver que para ler os 32 setores o disco fará apenas 5 rotações. A figura 6 b mostra o arranjo físico dos setores em uma trilha com a capacidade para 32 setores. Isto é porque. A mais simples mostra os setores adjacentes (veja Figura 6 a). . Assim. Conseqüentemente. Uma abordagem para se resolver este problema é intercalado os setores. colocar diversos setores físicos entre setores logicamente adjacentes.7 cilindros 440 Ou. Se não há espaço contíguo o suficiente para conter um arquivo inteiro. Palavra mais próxima para a tradução da palavra inglesa extent. especificamente porque significa que o arquivo como todo pode ser acessado com o mínimo número de posicionamento. o gerenciador de arquivo tenta coloca-los fisicamente contíguos a partir do fim do arquivo. mas o tamanho do cluster pode ser fixado para qualquer valor entre 1 e 65535 setores. Para fazer isto. o administrador estabelece o tamanho do cluster a ser usado num disco quando é inicializado. Setores logicamente adjacentes ocorrem em intervalos de 5 setores físicos. conseqüentemente o posicionamento ainda mais. assim todos os cluster num disco são do mesmo tamanho. . trilhas e cilindros (se é grande o suficiente) formam um conjunto contíguo. Quando um programa acessa um arquivo. Clusters: Uma terceira visão de organização de setores. Para ver um arquivo como uma série de clusters e ainda manter a visão de setores. o grau de contigüidade física é determinado pelo fator de intercalação. Se existe muito espaço livre em disco. os administrador do sistema decide quantos setores existirá em um cluster. todos os setores neste cluster podem ser acessados sem a necessidade de um posicionamento adicional. é uma visão mantida pelo gerenciador de arquivos do sistema operacional. clusters maiores garante a leitura de mais setores sem fazer posicionamentos. Em muitos sistemas. ele enxerga o arquivo como uma série de cluster (agrupamento) de setores.Duas divisões da organização de 32 setores numa trilha. Um cluster é um número fixo de setores contíguos2. A FAT contém uma lista ligada de todos os cluster num arquivo ordenado de acordo com a ordem lógica dos setores que eles contêm. pode ser possível fazer um arquivo consistir de clusters inteiramente contíguos. é tarefa do gerenciador mapear as partes lógicas do arquivo para suas correspondentes localizações físicas. (b) Setores intercalados com um fator de intercalação: 5. e uma vez que um cluster foi encontrado no disco. Cada parte é uma extensão. o arquivo é dividido em duas ou mais parte não contíguas. O valor default é três setores de 512 bytes por cluster. Extensão3: A visão final de organização de setores representa mais uma tentativa de enfatizar a contigüidade física de setores num arquivo. (a) Visão mais simples da organização de setores nas trilhas. o gerenciador liga os setores lógicos ao cluster físico ao qual eles pertencem usando a tabela de alocação de arquivos (FAT. 2 3 Não é bem fisicamente contíguo. Já que clusters representam grupos de setores fisicamente contíguos. Por exemplo.file allocation table).Figura 6 . na estrutura física de discos usado pelo sistema VAX. Isso é uma boa situação. Quando acontece isto dizemos que o arquivo consiste de uma extensão: todos os setores. Quando novos clusters são adicionados à um arquivo. também projetada para melhorar a performance. (a)organização em setores: sem considerar o tamanho de um registro ou outro agrupamento de dados. ou permitir que um registro ultrapasse um setor. A segunda opção tem a vantagem de não perder espaço com a fragmentação interna. Outra fonte potencial de fragmentação interna resulta do uso de clusters. (b) organização em bloco: a quantidade de dados transmitidos num acesso dependem do tamanho do bloco. não haverá uma ocupação conveniente entre registros e setores.5. Todo acesso envolve transmissão de um número integral de setores.mas em números inteiros de blocos definidos pelo usuário cujo tamanho pode variar. por exemplo. No endereçamento por blocos. então deve-se adicionar um ou mais extensões. 1535 bytes estaria perdido devido a fragmentação interna. um esquema de endereçamento de blocos seria algum múltiplo de 300 bytes dependendo da necessidade do programa. mas tem a desvantagem que os registros são recuperados acessando dois setores. Um bloco é geralmente organizado para manter um número integral de registros lógicos. há fragmentação interna na última extensão do arquivo. não seria perdido espaço devido a fragmentação interna e não existiria a necessidade de carregar dois blocos para recuperar um registro. blocos são freqüentemente referidos como registro físico. Os blocos são superiores aos setores quando a alocação física de espaço para registros corresponde a sua organização lógica.3. O termo fator de bloco é usado para indicar o número de registros que são armazenados em cada bloco num arquivo. o tamanho de um setor é 512 bytes e o tamanho de todos os registros num arquivo é 300 bytes. Fragmentação: Geralmente. Lembre-se que o cluster é a menor unidade de espaço que pode ser alocada para um arquivo. Quando o número de bytes num arquivo não é o múltiplo exato do tamanho do cluster. os dados estão agrupados fisicamente em setores. Os blocos podem ser de tamanho fixo ou variável. se cluster consiste de três setores de 512 bytes. Se. Há discos que permitem o endereçamento por setores e por blocos. Esta perda de espaço dentro de um setor é chamada de fragmentação interna. Assim como setores. cada bloco de dados é geralmente acompanhado por um ou mais subblocos extras. de modo que o início de um registro poderá ser encontrado num setor e o seu final em outro. contendo informações extras sobre o bloco de dados.Organização em setores x Organização em blocos. dependendo das exigências do projetista do arquivo.mas se não há espaço para fazer isso. A primeira opção tem a vantagem que qualquer registro pode ser recuperado em apenas um setor. mas tem a desvantagem de deixar uma enorme quantidade de espaço sem uso dentro de cada setor. Há duas maneiras de lidar com esta situação: armazenar um registro por setor. 1. em . todos os setores num determinado disco deve conter o mesmo número de bytes. A Figura 7 ilustra a diferença entre uma visão dos dados numa trilha dividida em setores e outra em blocos. Assim. Organização de Blocos Às vezes trilhas de discos não são divididas em setores. se possuíssemos um arquivo com registros de 300 bytes. Figura 7. por exemplo o tamanho. Por exemplo. Assim. um arquivo contendo um byte usaria 1536 no disco. Uma organização em blocos não apresenta o problema de fragmentação de setores porque os blocos podem variar em tamanho para preencher a organização lógica dos dados. pois deixa o programador (ganha mais tarefa também) determinar como os dados podem ser organizados fisicamente em disco. assim há menos espaço consumido pelos 300 bytes do marcador que acompanha cada bloco. a preformatação envolve armazenar. (observe que o resultado foi truncado porque um bloco não pode ser colocado em mais de uma trila). Alguns dos marcadores consistem de informação que são armazenadas no disco durante a preformatação.38 1. O número de blocos por trilha pode ser expresso como: 20. ou se é 60? Se há registros de 100 por bloco. . O que aconteceria. no exemplo anterior. dos dados contidos nos blocos. 1. ao invés de setores. Pode-se concluir deste exemplo que fatores de bloco maiores sempre leva a uma utilização mais eficiente do disco? Não necessariamente. A preformatação também coloca gaps (espaços) e marcas de sincronização para ajudar o mecanismo de leitura/escrita distinguir os setores. Queremos armazenar um arquivo contendo registros de 100 bytes no disco. quase sempre perde-se espaço no fim da trilha.000 = 15. temse o problema de fragmentação interna novamente. Suponha que temos um disco endereçável por bloco com 20. existem mais informações que não seja dados propriamente dito. que é feita antes que o disco possa ser usado. O número de blocos pode ser colocado numa trilha de 20. Marcadores Interblocos Blocos e setores exigem que uma certa quantidade de espaço seja alocada no disco na forma de marcadores. Desde que o número e tamanho dos blocos podem variar de uma aplicação para outra.300 Apenas 3 blocos ou 180 registros pode ser armazenados por trilha. Como podemos ver.000 bytes de dados e usa 6.6. Se há registros de 100 bytes por bloco. no inicio de cada setor. Vejamos exemplo a seguir.000 =3 6.3. pode resultar num ganho em tempo e eficiência. um maior fator de bloco pode levar a um mais eficiente uso de armazenamento. a quantidade relativa de espaço ocupado pelos marcadores podem variar quando o endereçamento por blocos é usada.000 bytes por trilha. Quanto maior for o tamanho do bloco maior será o potencial de fragmentação interna numa trilha. Já que podemos colocar somente um número inteiro de bloco numa trilha e as trilhas são de tamanho fixo. em relação aos blocos do que em relação aos setores. se fosse considerado o fator de bloco igual a 98? Ou 97? A flexibilidade introduzida pelo uso de blocos. quando o marcador é levado em conta. cada bloco contém 1000 bytes de dados e usa 300 + 1000 ou 1300 bytes de espaço em uma trilha. informações como: endereço do setor. Em discos endereçáveis por setores.bytes. Em discos endereçáveis por blocos. Quando os blocos são grandes. 15 blocos ou 150 registros podem ser armazenados por trilha. Quantos registros podem ser armazenado por trilha se o fator de bloco é 10. Logo. menos blocos são necessários para conter um arquivo. cada bloco contém 6. mas desta vez ela ocorre dentro de uma trilha. Já que subblocos e interblocos (marcadores) devem ser fornecidos com todo bloco. endereço da trilha e condições (se o setor é útil ou defeituoso). alguns dos marcadores são invisíveis ao programador. mas alguns deles podem ser encontrados pelo programador.000 bytes pela expressão: 20. e a quantidade de espaço usado por subblocos e interblocos é equivalente a 300 bytes por blocos.300 Portanto.300 bytes por trilha. Por exemplo.3.. de modo que o setor que se quer ler esteja sob o cabeçote de R/W.7. os dados gravados no setor podem ser transferidos. onde o disco é dedicado a apenas um processo.5 mseg. o tempo necessário para transferir um setor é 1/32 de uma rotação ou 0. da distância que o braço tem que se mover. também o cabeçote de leitura e escrita necessita se movimentar apenas a distância de uma trilha. Tempo de partida (s) 2. O custo de Acesso a disco Um acesso a disco pode ser dividido em três operações físicas distintas..3 x n + 20 mseg Atraso rotacional: Atraso rotacional refere-se ao tempo que o disco leva para rodar.7 mseg.1. cada uma com o seu próprio custo: tempo de posicionamento. Jornada de um Byte O que acontece quando um programa envia um byte para um arquivo num disco? Sabemos como o programa faz (WRITE(. onde vários processo estão concorrendo para o uso do disco. do que em ambiente monousuário. se é necessário acessar setores de dois arquivos que estão nos extremos opostos de um disco (um no cilindro mais interno e o outro no mais externo) o posicionamento se torna mais lento. Tempo de posicionamento: o tempo de posicionamento é o tempo necessário para mover o cabeçote de I/O ou cilindro correto. O tempo de posicionamento é maior no processo R/W em ambientes multiusuários.4. 1. se há 32 setores/trilha. é claro. as mais importantes são: 1. o tempo de transferência de um setor depende do número de setores por trilha. Tempo de transferência: Uma vez que o setor a ser lido está sob o cabeçote de R/W. atraso rotacional. Tempo de travessia ( n) Estes dois valores podem ser aproximados para uma função linear de forma: F(n)= m x n + s Onde m é uma constante que depende de cada drive. Na média o atraso rotacional é a metade de uma revolução ou 8. o posicionamento é feito somente após todas as trilhas de um cilindro forem processadas. Por exemplo o tempo de posicionamento em um disco de 20 megabytes usados em PC’s pode ser aproximado por: f (n)= 0. Os discos geralmente tem uma rotação de 3600 rpm que é uma revolução por 16. O tempo de transferência é dado pela fórmula: Tempo de transf = Número de bytes transferidos x tempo de rotação Número de bytes numa trilha Se o disco é dividido em setores. O posicionamento envolve diversas operações que gastam tempo. Por outro lado.)) e como os bytes são armazenados num disco.3 mseg. tempo de transferência. Se é necessário acessar um arquivo seqüencialmente e o arquivo está distribuído em vários arquivos consecutivos. mas não sabemos o que . O tempo de posicionamento gasto durante um acesso ao disco depende. 4. o gerenciador de arquivo precisa saber onde se encontra o fim do arquivo – a localização física do último setor do arquivo. para um arquivo chamado TEXT armazenado em algum lugar no disco. Uma vez identificado o arquivo desejado e verificado se o acesso é legal.. possivelmente. cada um projetado para gerenciar uma parte diferente dos recursos do computador. Esta informação é obtida na FAT.O comando WRITE ( ) no programa diz ao SO enviar um caracter para o disco e dá ao SO a localização do caractere. Suponha que será gravado um byte representado pela letra “P” guardado na variável c.). O resultado do comando WRITE ( ) é chamada ao SO que possui a tarefa de completar e “fiscalizar” o resto da jornada deste byte (Figura 8). O Gerenciador de Arquivo O sistema Operacional (SO) não é um único programa. O byte começa sua jornada em algum lugar na memória principal. Este subconjunto de subprogramas é chamado de gerenciador de arquivo. Figura 8. O byte que usar vários meios de transporte diferentes. até acidentes. Como “P” será colocado no fim do arquivo. 1. do tipo caractere.C. como conteúdo da variável c. o gerenciador de arquivo deve saber onde no arquivo TEXT depositar o caracter “P”. a jornada que o byte pode ser representada pelo comando: WRITE (TEXT. O gerenciador de arquivo verifica as características lógicas do arquivo: se arquivo foi aberto. Entre estes programas estão aqueles que trabalham com tarefas relacionada a arquivos e dispositivos de I/O. Do ponto de vista do programa. atrasos e.1) Mas a jornada é muito maior do que sugere este simples comando. Depois o controle é retomado pelo programa..1. se é permitido gravar no arquivo etc. para que tipo de arquivo o byte está sendo enviado (arquivo binário. É uma jornada marcada por obstruções. . ou texto.acontece entre o programa e o disco. mas uma coleção de programas.. alguns lentos outros rápidos.etc. 1.O gerenciador de arquivo move “P” da área de dados do programa para o buffer. Tal dispositivo de propósito especial é chamado de processador de entrada/saída (I/O). veja Figura 9. Esta informação poderá vir em forma de um pequeno programa que o sistema operacional constrói e o processador de I/O executa. ao invés de enviar o setor imediatamente para o disco. 1. Em outras palavras. Agora o byte “viaja” em direção do disco onde o caminho deve ser mais lento e mais limitado que na RAM.4. o buffer habilita o gerenciador de arquivo assegurar que a organização dos dados RAM esteja em conformidade com a organização dos mesmos no disco.4. O processo de montagem e desmontagem de grupos de byte para a transmissão de/para dispositivos externos são tão especializados que não é adequado deixar a CPU gastar seu valioso tempo fazendo I/O quando um dispositivo mais simples pode realizar este trabalho. O sistema de buffer de I/O permite ao gerenciador de arquivo ler e escrever dados em unidades de tamanho do bloco ou de setor. o gerenciador de arquivo determina se o setor que conterá “P” já está na RAM ou se precisa ser carregado. Figura 9.2.3. o gerenciador de arquivo espera para saber se ele pode acumular mais bytes que vai para o mesmo setor antes de realmente transmiti-lo ao disco. Um processador de I/O pode ser um simples chip capaz de pegar um byte e passá-lo à frente. Uma vez que o setor já está no buffer na RAM. todas as atividades do nosso byte ocorreram na memória principal (RAM) e provavelmente foram executadas pela CPU. livrando a CPU de realizar tal tarefa. ou um pequeno computador capaz de executar programas sofisticados e comunicar com muitas dispositivos independentemente. Devido ao gargalo criado por essas diferenças de velocidade e capacidade do caminho. o byte pode ter que esperar que um caminho externo esteja disponível. O processador de I/O Até agora. O Buffer de I/O Depois. . o gerenciador de arquivo pode depositar “P” na sua posição apropriada. quantos dados existem e onde colocá-los no disco. Na verdade. então fazer a leitura deste no disco. O gerenciador de arquivo deve encontrar espaço no buffer de I/O para o byte. Na maioria dos computadores o gerenciador de arquivos diz ao processador de I/O que há dados no buffer para serem transmitidos ao disco. sendo cada item chamado campo ou atributo. O armazenamento de um arquivo é feito. A seguir. por exemplo. Isto causa uma dificuldade na localização dos registros e uma perda de eficiência. que são Arquivo Seqüencial. crescem também os problemas de eficiência do armazenamento dos arquivos e do acesso a seus registros. não encerra grandes problemas no que diz respeito à distribuição dos registros dentro de um arquivo. 2. via de regra. A maneira intuitiva de armazenar um arquivo consiste na distribuição dos seus registros em uma ordem arbitrária. é identificado um único registro do arquivo. sendo. aquela na qual os registros são gerados. é formado por uma seqüência de itens. Arquivo Indexado. O cabeçote de R/W deve posicionar-se na trilha e esperar até que o disco rotacione de modo que o setor desejado esteja sob o cabeçote. Arquivo Seqüencial Indexado. O drive é instruído pelo controlador a mover o cabeçote de R/W para a trilha e o setor do disco onde o byte será armazenado. e uma.4.1. após a apresentação da terminologia usada neste capítulo. Uma chave primária é uma chave que apresenta um valor diferente para cada registro do arquivo. principalmente durante as fases preliminares da geração de um arquivos. Uma chave secundária difere de uma primária pela possibilidade de não possuir um valor diferente para cada registro. Usualmente a chave primária é formada por um único campo. são apresentadas introduções sobre quatro estratégias de organização de arquivos voltadas para o acesso por meio de chaves primárias. Uma vez que a trilha e o setor foram localizados. lido ou gravado todo um bloco e não apenas um registro lógico. um após o outro. dado um valor da chave primária.2. O comprimento dos valores de um atributo pode ser constante para todos os registros do arquivo. Arquivo Direto. Assim. ao disco. Cada campo possui um nome.1. Arquivo Invertido. ou variável. em cada leitura ou gravação. sendo a sofisticação das técnicas de armazenamento e recuperação de dados uma conseqüência da necessidade de acesso rápido a registros pertencentes a grandes arquivos ou. um valor de uma chave secundária identifica um conjunto de . Uma chave é uma seqüência de um ou mais campos em um arquivo. 2. dentro da área destinada a contê-lo. um de cada vez. cada um deles representando um objeto ou entidade. via de regra.4. Organização de Arquivos 2. de tal forma que. o controlador de disco. A medida que cresce o volume de dados e/ou a freqüência e a complexidade dos acessos. simplesmente. Terminologia Um arquivo é formado por uma coleção de registros lógicos. Um registro lógico. Controlador de Disco A tarefa de controlar as operações do disco é feita por outro dispositivo. o processador de I/O (ou controlador) pode enviar os bytes. desde que a freqüência de acessos aleatórios a registros não seja muito elevada. por blocos de registros lógicos (um bloco é chamado registro físico). Introdução O armazenamento de pequenos volumes de dados. um tipo e um comprimento. porém esta técnica intuitiva é bastante usada. arquivos muito solicitados. ou simplesmente registro. Cada item corresponde a uma característica ou propriedade do objeto representado. voltada para acesso por meio de chaves secundárias. Esta ordem pode ser. essa chave é então chamada chave de ordenação. é facilitado se a chave de acesso . também. Já que os registros em arquivos seqüenciais são armazenados em sucessão contínua . Argumento de pesquisa é o valor da chave de acesso em uma operação. Chave de acesso é a chave utilizada para identificar o(s) registro(s) desejado(s) em uma operação de acesso a um arquivo. Introdução aos Arquivos Seqüenciais A organização de arquivos sequenciais é a mais conhecida e mais freqüentemente usada. metade de um arquivo sequencial tem que ser lido para recuperar um registro. NÚMERO 100 150 200 250 300 350 400 450 500 550 NOME Pedro Leandro Rodrigo Maria Celso Ana João Gisele Jack Sandra IDADE 23 20 19 30 27 42 22 23 21 24 SALÁRIO 1000 500 270 5000 2500 9000 2100 1300 800 2400 Esta organização. A ordem lógica e física dos registros armazenados em um arquivo seqüencial é a mesma . uma perda de flexibilidade por não acomodar com simplicidade as operações de modificação do arquivo. é apresentado um exemplo de arquivo seqüencial. a fitas magnéticas. Em média. Se um mecanismo de leitura/gravação é posicionado para recuperar um registro em particular. quando o acesso a sucessivos registros em alta velocidade é um requisito do processamento . Os registros em arquivos sequenciais sem chave estão ordenados em série. Os Arquivos Seqüenciais são associados. Chave de um registro é o valor de uma chave primária em um particular registro do arquivo Chave de ordenação é a chave primária usada para estabelecer a seqüência na qual devem ser dispostos (física ou logicamente) os registros de um arquivo. dado um argumento de pesquisa. historicamente. Cada registro lógico do arquivo com chave tem um item de dado chamado chave que pode ser usado para ordenar os registros. O principal uso dos arquivos sequencias é o processamento em série ou sequencial de registros. Os arquivos sequenciais podem ter chave ou não. no qual é usado como chave de ordenação o atributo NÚMERO.3. O acesso a uma registro. acessar o registro N do arquivo(começando no início do arquivo) requer que os registros N-1 também sejam lidos. A vantagem de poder acessar rapidamente o registro seguinte torna-se uma desvantagem quando o arquivo é usado para acessar um outro registro diferente do registro "seguinte". 2. então ele pode acessar rapidamente o registro seguinte do arquivo. que representa um aperfeiçoamento em relação àquela na qual os registros são dispostos aleatoriamente.registros. representa. sendo que geralmente cada novo registro é colocado no final do arquivo. devido a natureza seqüencial do meio de gravação. Mas os arquivos seqüenciais são também armazenados em dispositivos de acesso aleatório. Na tabela abaixo. um índice é sempre específico para uma chave de acesso. 4. acrescido em um índice (estrutura de acesso) constitui um arquivo seqüencial indexado. não há vantagem na seqüencialidade do arquivo. o que faz com que a área ocupada pelo índice seja menor do que aquela ocupada pelos dados. Introdução aos Arquivos Seqüenciais Indexados Quando em um arquivo seqüencial o volume de acessos aleatórios torna-se muito grande. para o arquivo auxiliar. 3. Inserção de um Registro A maneira mais comum de se processar inserções de um registro em um arquivo sequencial S consiste em montar um arquivo T de transações que contém os registros a serem inseridos ordenados pela mesma chave de ordenação de S.até o local de inserção .3.coincide com a chave de ordenação (ou com sua parte inicial). associada ao arquivo. 2. pois. A técnica anteriormente descrita é utilizada pois a inserção de um registro isolado tem um custo proibitivo. gerando o arquivo A que é uma versão atualizada de S. cada um deles associando um valor da chave de acesso a um endereço no arquivo.Posicionar-se no inicio do arquivo. configura-se a necessidade de utilização de uma estrutura de acesso. 5. dado um argumento de pesquisa. Assim. ocupa um espaço bem menor do que o registro de dados correspondente.3.Índices A finalidade de um índice é permitir rápida determinação do endereço de um registro do arquivo. Com isto a pesquisa sobre o índice pode ser feito com maior rapidez do que se fosse feita diretamente sobre o arquivo de dados correspondente. Outra maneira de se proceder a inserção de um registro é seguindo este procedimento: 1. Usualmente. na memória secundária. Um índice é formado por uma coleção de pares. pois implicaria no deslocamento de todos os registros com chaves superiores ao que foi inserido. O endereço identifica a posição onde está armazenado o registro. formada por um par (chave do registro. um arquivo seqüencial indexado possui áreas de extensão que são utilizadas para a implementação da operação de inserção de registros. Além do arquivo seqüencial e do índice. que apresenta o arquivo seqüencial indexado: .4. Este fato constitui a justificativa maior para a utilização dos índices. . Veja a tabela abaixo.Identificar posição de inserção. nos demais casos. que ofereça maior eficiência na localização de um registro identificado por um argumento de pesquisa do que os métodos vistos para arquivos seqüenciais.Copiar todos os registros.Copiar registros restantes para o arquivo auxiliar. endereço do registro).O arquivo T pode ser usado como uma extensão de S .Adicionar registro no arquivo auxiliar.Substituir arquivo antigo pelo arquivo auxiliar 2. cada entrada do índice. até assumir um tamanho que justifique a efetivação da operação de intercalação quando os arquivos S e T são intercalados. Um arquivo seqüencial. 6. 2. após a criação do arquivo. em um arquivo seqüencial indexado. Naquele processo. porque nesses não é viável a implementação da operação de inserção de registros do mesmo que nos arquivos seqüenciais. a maioria dos registros muda de endereço.Áreas de Extensão A área de extensão (também chamada área de overflow) destina-se a conter os registros inseridos. o que obrigaria uma completa alteração nas entradas do índice.NÚMERO ENDEREÇO 100 150 200 1 2 3 1 2 3 NÚMERO NOME 100 150 200 PEDRO JOÃO MARIA SALÁRIO 3000 1500 2500 250 4 300 5 |---------ÍNDICE---------| 4 250 CARLA 3000 5 300 MAX 2000 |-----------ÁREA DE DADOS NO DISCO------------| . a cada atualização do arquivo. Uma possível implementação de áreas de extensão em um arquivo seqüencial indexado consiste em destinar um em cada registro da área principal um campo de elo para conter o endereço da lista encadeada de seus sucessores (ou antecessores) alocados na área de extensão. conforme a tabela: NÚMERO ENDEREÇO 1 100 150 175 200 250 275 300 1 2 2 3 4 4 5 2 3 4 5 NÚMERO NOME 100 150 200 250 300 PEDRO JOÃO MARIA CARLA MAX ELO 10 20 - |----------ÁREA DE DADOS NO DISCO-----------| |---------ÍNDICE---------| NÚMERO NOME 10 20 30 40 50 175 275 BILL NARA ELO - |----------------ÁREA DE EXTENSÃO----------------| . Áreas de extensão são necessárias em arquivos seqüenciais indexados. Ela constitui uma extensão da área principal de dados do arquivo. 2.5. Introdução aos Arquivos Indexados Nos arquivos seqüenciais indexados, o compromisso de manter os registros fisicamente ordenados pelo valor da chave de ordenação, com o objetivo de prover um acesso serial eficiente, acarreta uma série de problemas, principalmente no que diz respeito à operação de inserção de um registro, conduzindo à necessidade de utilização de áreas de extensão e efetivação de reorganizações periódicas. À medida que decresce a freqüência de acessos seriais, relativamente à freqüência de acessos aleatórios, a manutenção da seqüencialidade física do arquivo encontra uma compensação cada vez menor em termos de eficiência de acesso, até tornar-se antieconômica. A partir deste ponto, torna-se mais conveniente o uso de um arquivo indexado, no qual os registros são acessados sempre através de um ou mais índices, não havendo qualquer compromisso com a ordem física de instalação dos registros. A liberdade na escolha do endereço no qual um registro é armazenado representa um ganho de flexibilidade que permite maior eficiência, principalmente na operação de inserção de um registro, conduzindo, também, a uma simplificação da estrutura geral do arquivo, sendo dispensados os mecanismos complexos de administração de áreas de extensão. Veja a tabela abaixo, que apresenta o indexado: NÚMERO ENDEREÇO 100 150 200 250 4 3 1 5 1 2 3 4 NÚMERO 200 300 150 100 NOME PAULO JOSÉ MARIA MARISA SALÁRIO 3100 4500 2500 5000 300 2 |---------ÍNDICE---------| 5 250 FABIO 2500 |-----------ÁREA DE DADOS NO DISCO------------| - Índices Em um arquivo indexado, podem existir tantos índices quantas forem as chaves de acesso aos registros. Um índice consiste de uma entrada para cada registro considerado relevante com relação à chave de acesso associada ao índice. As entradas do índice são ordenadas pelo valor da chave de acesso, sendo cada uma delas constituída por um par (chave do registro, endereço do registro). A seqüencialidade física das entradas no índice visa a tornar mais eficiente o processo de busca e permitir o acesso serial ao arquivo. Um índice é dito exaustivo quando possui uma entrada para cada registro do arquivo e seletivo quando possui entradas apenas para um subconjunto de registros. O subconjunto é definido por uma condição relativa à chave de acesso e/ou a outros atributos do arquivo.Um exemplo de índice seletivo seria o índice dos funcionários estáveis (há mais de 10 anos na empresa) sobre o cadastro geral de funcionários de uma empresa. O maior problema relacionado com a utilização de arquivos indexados diz respeito à necessidade de atualização de todos os índices, quando um registro é inserido no arquivo. Atualizações nos índices também são necessárias quando a alteração de um registro envolve atributos associados a índices. Nos arquivos seqüenciais indexados, a necessidade de alteração dos índices é eliminada pelo uso de áreas de extensão e encadeamento na implementação de inserções; no entanto, esta estratégia não é condizente com a idéia de arquivos indexados, nos quais a manutenção constante dos índices é necessária. 2.6. Introdução aos Arquivos Diretos A idéia básica de um arquivo direto consiste na instalação dos registros em endereços determinados com base no valor de uma chave primária, de modo que se tenha acesso rápido aos registros especificados por argumentos de pesquisa, sem que haja necessidade de percorrer uma estrutura auxiliar (índice). Um arquivo direto é semelhante a um arquivo indexado, no sentido de que, nos dois casos, o objetivo principal é a obtenção de acesso aleatório eficiente. Em um arquivo direto, aos invés do índice é usada uma função que calcula o endereço do registro a partir do argumento de pesquisa. As duas organizações possuem diferenças importantes, além do modo pelo qual é feito o acesso. Uma delas é o fato de que nos arquivos indexados, ao contrário dos diretos, o endereço onde um registro é armazenado independe do valor de sua chave, e uma outra, muito importante, diz respeito a acessos seriais, que nos arquivos indexados são providos por meio de índices e nos arquivos diretos não são previstos, de acordo com a idéia básica. Veja a tabela abaixo, que apresenta o arquivo direto: chave: 150---> E=F(chave) ---> E = 3 |--------> 2 3 150 4 5 250 FABIO 2500 |-----------ÁREA DE DADOS NO DISCO------------| - Cálculo de Endereços O primeiro problema com os arquivos diretos é o da determinação de uma função F, que transforme o valor da chave C de um registro no endereço E que lhe corresponde no arquivo. Podemos considerar dois tipos de funções, sendo o primeiro constituído pelas funções determinísticas, as quais associam um único valor da chave de acesso a cada endereço. Este tipo de função apresenta vantagens evidentes; no entanto, é impossível, em termos práticos, encontrar uma função determinística simples para um grande número de registros. Aquelas que poderiam ser usadas seriam tão complexas que eliminariam as vantagens do acesso direto, além de necessitarem adaptações a cada inserção sofrida pelo arquivo. Não têm, portanto, maior interesse prático. O segundo tipo é formado pelas funções probabilísticas, as quais geram para cada valor da chave um endereço "tão único quanto possível", podendo gerar, para valores distintos de chave, o mesmo endereço, fato este que é denominado colisão. - Tratamento das Colisões Um dos aspectos mais importantes na organização de arquivos diretos diz respeito ao problema das colisões, que é uma conseqüência do uso de funções não determinísticas para a transformação dos valores da chave de acesso em endereços do arquivo. Para se tratar as colisões, as soluções mais freqüentes usadas são Endereçamento Aberto com Pesquisa Seqüencial e Encadeamento. A primeira consiste em fazer uma busca sobre o arquivo para localização de um endereço livre, sendo nele armazenado o registro. A pesquisa do endereço livre é de forma seqüencial, ou seja, se o endereço E gerado pela chave estiver ocupado, o próximo a ser consultado será o endereço E + 1, E + 2,...,,...,E - 1 até se encontrar um lugar vago para armazenar o registro. Na segunda solução, todos ou parte dos registros que colidem em um mesmo endereço são juntados em uma lista encadeada, à qual se tem acesso por meio do endereço gerado pela função de MARIA 2500 NÚMERO 1 200 NOME PAULO SALÁRIO 3100 aleatorização. As duas estratégias mais usadas são a utilização de áreas de extensão e encadeamento puro. 2.7. Introdução aos Arquivos Invertidos Esta organização é baseada em uma mudança nos papeis de registro e atributos, de tal forma que, em vez de serem coletados os valores dos atributos para cada registro, são identificados os registros que possuem cada um dos particulares valores da chave de acesso considerada. A cada um dos valores da chave de acesso, presentes no arquivo, é associada uma lista de identificações de registros, chamada lista invertidas. As técnicas usuais na organização de índices são válidas também para este caso, devendo ser tomado o devido cuidado com o fato de que, em um arquivo invertido, a cada valor da chave de acesso está associado não apenas um endereço do registro, mas sim um conjunto de endereços dos registros que possuem aquele valor da chave. O conjunto de listas invertidas associado a uma chave de acesso é chamado inversão, sendo que um arquivo invertido pode assumir uma ou mais inversões. Na tabela abaixo, é representado um arquivo invertido com duas inversões associadas à chave secundária IDADE, uma contendo os ENDEREÇOS e outra NÚMEROS. IDADE ENDEREÇOS 20 22 23 25 27 2 1 4 6 3 10 7 8 5 9 1 2 3 4 5 IDADE NÚMEROS 20 22 23 25 27 200 350 250 600 150 550 450 300 400 100 6 7 8 9 NÚMERO 350 200 150 250 400 600 450 300 100 NOME PEDRO GISA MAX SANDRA PAULO CARLA ROBSON CELSO RENATA LEANDRO IDADE 22 20 27 23 22 25 27 20 20 25 10 550 Na primeira inversão, os registros são identificados por seus endereços físicos. Esta modalidade apresenta a vantagem de permitir o acesso direto ao registro, mas acarreta o problema de que as listas são válidas apenas para aquela disposição física dos registros, sendo que, caso o arquivo venha a sofrer uma reorganização que envolva mudança nos endereços dos registros, todas as inversões deverão ser novamente geradas. Uma alternativa para este problema consiste na identificação dos registros por meio de uma de suas chaves primárias, como na segunda inversão. Com isto as listas invertidas passam a ser independentes da localização física dos registros, havendo, no entanto, perda de eficiência no acesso, em virtude da necessidade de determinar o endereço do registro uma vez obtida a sua chave primária na lista. Como são determinados o endereço de um registro num arquivo direto? a) Através de uma lista invertida. -Utilizam índices. d) O uso de ponteiros. b) O uso de uma função probabilística. d) Uma estrutura de dados usada para identificar um arquivo seqüencial. O que é inversão num arquivo invertido? a) Consiste na inversão da ordem dos caracteres de um arquivo. c) Através de uma função. 2. 6. c) É a chave que abria a sala da porta da sua sala na 1ª série. que precisam ser RAM.2. . Arquivo Seqüencial Seqüencial Indexado Indexado Direto Invertido Vantagens Desvantagens .Operações de modificações não são simples. reorganizadas. Marque uma desvantagem do arquivo indexado em relação ao arquivo direto. de colisões .As listas invertidas valem apenas para aquela invertida. 2. 3.9.Necessidades de áreas de extensão. . O que é registro? a) É uma seqüência de itens. ambas são a mesma coisa. O que é chave primária? a) É uma seqüência de uma ou mais campos em um arquivo. seqüencial? a) O uso de índices.Registros sem compromisso com armazenamento físico. . b) Através de um índice. c) É uma entidade de um banco de dados relacional orientado a objetos.Acesso direto ao registro após localização da lista .8. c) O uso de derivadas direcionais. . disposição física do arquivo. c) Colisão de endereços. d) Através de chaves secundárias associadas a cada um dos campos.Determinar funções que gerem menor número -Acesso direto. b) É uma chave que apresenta uma valor diferente para cada registro. chamados de campos ou atributos. 5. b) É uma seqüência de um ou mais campos em um arquivo. -Não existem áreas de . sem necessidade do índice. d) Uma lista de identificações associada a cada chave de acesso.Acessos seqüenciais mais eficientes. a) Nenhuma. Qual é a vantagem do arquivo seqüencial indexado sobre o arq. b) Funções compostas exaustivas c) O uso de índices d) Chaves de registro 4. que lista as vantagens e desvantagens das várias organizações de arquivos.Atualização do índice quando da inserção de extensão um registro. Exercícios 1. que agilizam a consulta por estarem na . b) É um conjunto de listas invertidas associado a uma chave de acesso. Quadro Comparativo entre as Organização de Arquivos Eis um quadro comparativo. Este nome deve ser válido no sistema operacional que estiver sendo utilizado. Abrindo e fechando um arquivo O sistema de entrada e saída do ANSI C é composto por uma série de funções.3. Abrir um arquivo texto para gravação. "r+b" Abre um arquivo binário para leitura e escrita. Seu protótipo é: FILE *fopen (char *nome_do_arquivo.1. Arquivos em C 3. será criado. Abre um arquivo texto para gravação e leitura. p será então um ponteiro para um arquivo. O nome_do_arquivo determina qual arquivo deverá ser aberto. no caso de arquivo não existente anteriormente. O mesmo que "a+" acima. cujos protótipos estão reunidos em stdio. no caso de arquivo não existente anteriormente. Podemos declarar um ponteiro de arquivo da seguinte maneira: FILE *p. só que o arquivo é binário. mas uma definição usando o comando typedef. Se já existir. É usando este tipo de ponteiro que vamos poder manipular arquivos no C. só que o arquivo é binário. como no modo "w" anterior. O mesmo que "w+" acima. escrever: . o conteúdo anterior será destruído. "rb" Abre um arquivo binário para leitura.char *modo). "wb" Cria um arquivo binário para escrita. para abrir um arquivo binário para escrita. "w+b" Cria um arquivo binário para leitura e escrita. só que o arquivo é binário. Este não é um tipo propriamente dito. A tabela abaixo mostra os valores de modo válidos: Modo Significado "r" Abre um arquivo texto para leitura. se ele "a" já existir. O modo de abertura diz à função fopen() que tipo de uso você vai fazer do arquivo.h. O arquivo deve existir antes de ser aberto. como no modo "a" anterior.h. Se o arquivo não existir. ele será criado. "r+" Abre um arquivo texto para leitura e gravação. Acrescenta dados ou cria uma arquivo binário para leitura e escrita. só que o "a+b" arquivo é binário Poderíamos então. ou um novo arquivo será criado. "ab" Acrescenta dados binários no fim do arquivo. "w+" Se não existir. só que o arquivo é binário. o conteúdo "w" anterior será destruído. Abrir um arquivo texto para gravação. Os dados serão adicionados no fim do arquivo se ele já "a+" existir. O arquivo deve existir e pode ser modificado. Todas estas funções trabalham com o conceito de "ponteiro de arquivo". O mesmo que "r+" acima. fopen Esta é a função de abertura de arquivos. Se o arquivo existir. Esta definição também está no arquivo stdio. Cria um arquivo texto para leitura e gravação. Igual ao modo "r" anterior. Os dados serão adicionados no fim do arquivo ("append"). só que o arquivo é binário. ou um novo arquivo será criado. h.. se o programa não conseguir a memória necessária ou abrir o arquivo. A condição !fp testa se o arquivo foi aberto com sucesso porque no caso de um erro a função fopen() retorna um ponteiro nullo (NULL). /* o arquivo se chama exemplo. Fim de programa. para o sistema operacional. Uma vez aberto um arquivo. Normalmente. A função exit() se torna importante em casos como alocação dinâmica e abertura de arquivos pois nestes casos..bin". Poderíamos reescrever o exemplo da seção anterior usando agora o exit() para garantir que o programa não deixará de abrir o arquivo: #include <stdio. fp=fopen ("exemplo... if (!fp){ printf ("Erro na abertura do arquivo. . /* Declaração da estrutura fp=fopen ("exemplo."wb"). exit Aqui abrimos um parênteses para explicar a função exit() cujo protótipo é: void exit (int codigo_de_retorno). } . Num acesso randômico teremos que mexer nesta posição (ver fseek()). não temos que mexer nesta posição pois quando lemos um caractere a posição no arquivo é automaticamente atualizada. Esta função aborta a execução do programa. vamos poder ler ou escrever nele utilizando as funções que serão apresentadas a seguir.").")."wb"). Para tanto usa-se a . o código_de_retorno. return 0. há uma espécie de posição atual no arquivo. Toda vez que estamos trabalhando com arquivos.bin e está localizado no diretório corrente */ if (!fp) printf ("Erro na abertura do arquivo. Pode ser chamada de qualquer ponto no programa e faz com que o programa termine e retorne. } fclose Quando acabamos de usar um arquivo que abrimos.h> /* Para a função exit() */ main (void) { FILE *fp. exit (1). num acesso sequencial a um arquivo.h> #include <stdlib.bin". A convenção mais usada é que um programa retorne zero no caso de um término normal e retorne um número não nulo no caso de ter ocorrido um problema. devemos fechá-lo. Esta é a posição de onde será lido ou escrito o próximo caractere. Para utilizá-la deve-se colocar um include para o arquivo de cabeçalho stdlib.FILE *fp. a melhor saída pode ser terminar a execução do programa. h> int main() { FILE *fp. int i. seu conteúdo é escrito no disco de uma vez. .FILE *fp). string[i]. Lendo e escrevendo caracteres em arquivos putc A função putc é a primeira função de escrita de arquivo que veremos. apenas para gravar aquele caracter. verifique o conteúdo do arquivo arquivo. O programa a seguir lê uma string do teclado e escreve-a. #include <stdio. Você verá que a string que você digitou está armazenada nele. for(i=0. o que é este "buffer"? Quando você envia caracteres para serem gravados em um arquivo.txt. O ponteiro fp passado à função fclose() determina o arquivo a ser fechado. fp). caractere a caractere */ fclose(fp). char string[100]. return 0. } printf("Entre com a string a ser gravada no arquivo:").h> #include <stdlib. para cada caracter que fossemos gravar."w"). as gravações seriam muito lentas. para escrita */ if(!fp) { printf( "Erro na abertura do arquivo"). /* Arquivo ASCII. estes caracteres são armazenados temporariamente em uma área de memória (o "buffer") em vez de serem escritos em disco imediatamente. 3. caractere por caractere em um arquivo em disco (o arquivo arquivo. /* Grava a string. fp = fopen("arquivo. A razão para se fazer isto tem a ver com a eficiência nas leituras e gravações de arquivos. Seu protótipo é: int putc (int ch. Assim estas gravações só serão efetuadas quando houver um volume razoável de informações a serem gravadas ou quando o arquivo for fechado.txt (você pode usar qualquer editor de textos).função fclose(): int fclose (FILE *fp). gets(string).2. Fechar um arquivo faz com que qualquer caracter que tenha permanecido no "buffer" associado ao fluxo de saída seja gravado. } Depois de executar este programa. i++) putc(string[i]. que será aberto no diretório corrente). A função retorna zero no caso de sucesso. tivéssemos que posicionar a cabeça de gravação em um ponto específico do disco. Mas. Se.txt". Escreve um caractere no arquivo. A função exit() fecha todos os arquivos que um programa tiver aberto. Quando o "buffer" estiver cheio. exit(1). feof EOF ("End of file") indica o fim de um arquivo. Ela retorna não-zero se o arquivo chegou ao EOF. usando as funções vistas nesta página. O programa a seguir abre um arquivo já existente e o lê. char c. . } while((c = getc(fp) ) != EOF) /* Enquanto não chegar ao final do arquivo */ printf("%c"."r"). /* imprime o caracter lido */ fclose(fp). caso contrário retorna zero. caracter por caracter.getc Retorna um caractere lido do arquivo. exit(0). } A seguir é apresentado um programa onde várias operações com arquivos são realizadas. /* Arquivo ASCII. gets(str).txt".h> #include <stdlib. para leitura */ if(!fp) { printf( "Erro na abertura do arquivo").h> int main() { FILE *fp. Os caracteres lidos são apresentados na tela: #include <stdio.h> void main() { FILE *p. Seu protótipo é: int feof (FILE *fp). e imprime-se algo nele. Protótipo: int getc (FILE *fp). #include <stdio. Outra forma de se verificar se o final do arquivo foi atingido é comparar o caractere lido por getc com EOF. frase[80] = "Este e um arquivo chamado: ". até que o final do arquivo seja atingido. return 0. é necessário verificar se um arquivo chegou ao fim. Às vezes. str[30]. int i. fp = fopen("arquivo. c). Para isto podemos usar a função feof(). char c. Verifique o exemplo.h> #include <string.h> #include <stdlib. o arquivo é fechado e novamente aberto para a leitura. Em seguida. /* Le um nome para o arquivo a ser aberto: */ printf("\n\n Entre com um nome para o arquivo:\n"). Primeiro o arquivo é aberto para a escrita. associado à porta serial) stdprn : dispositivo de impressão padrão (em muitos sistemas. para acessar os periféricos associados a eles. stdout)."w"))) /* Caso ocorra algum erro na abertura do arquivo.3. /* Le um novo caracter no arquivo */ } fclose(p).FILE *fp). por exemplo. str). /* Abre novamente para leitura */ p = fopen(str. /* Le o primeiro caracter */ while (!feof(p)) /* Enquanto não se chegar no final do arquivo */ { printf("%c". int tamanho. associado à porta paralela) Cada uma destas constantes pode ser utilizada como um ponteiro para FILE. /* Imprime o caracter na tela */ c = getc(p).p). } /* Se nao houve erro. para efetuar a leitura de um caracter a partir do teclado. frase[i]. .. Desta maneira.. imprime no arquivo e o fecha .if (!(p = fopen(str. for (i=0. Outros comandos de acesso a arquivos Arquivos pré-definidos Quando se começa a execução de um programa. fgets Para se ler uma string num arquivo podemos usar fgets() cujo protótipo é: char *fgets (char *str. ou : putc(ch."r"). i++) putc(frase[i]. para imprimí-lo na tela.. o sistema automaticamente abre alguns arquivos pré-definidos: stdin: dispositivo de entrada padrão (geralmente o teclado) stdout: dispositivo de saída padrão (geralmente o vídeo) stderr: dispositivo de saída de erro padrão (geralmente o vídeo) stdaux: dispositivo de saída auxiliar (em muitos sistemas. usar: ch =getc(stdin). /* Fecha o arquivo */ 3. pode-se.c). fclose(p). c = getc(p).*/ strcat(frase.*/ { /* o programa aborta automaticamente */ printf("Erro! Impossivel abrir o arquivo!\n"). exit(1). perror e fputs #include <stdio."w")) == NULL) { . tamanho. A função retorna zero. etc. o limite máximo de caracteres a serem lidos e o ponteiro para FILE. Escreve uma string num arquivo. stdin). fputs Protótipo: char *fputs (char *str. levando em conta que o ponteiro fp pode ser substituído por stdin. existem situações em que isto não ocorre. if((pf = fopen("arquivo. se um arquivo pode ser aberto. o que poderia acarretar erros de "estouro de buffer".h> #include <stdlib. porém. A função lê a string até que um caracter de nova linha seja lido ou tamanho-1 caracteres tenham sido lidos. como vimos acima. a função gets não tinha este controle. pode acabar o espaço em disco enquanto gravamos. A função fgets é semelhante à função gets().txt". A string resultante sempre terminará com '\0' (por isto somente tamanho-1 caracteres. se nenhum erro ocorreu e um número diferente de zero se algum erro ocorreu durante o acesso ao arquivo. Portanto. por causa do '\0'. Uma função que pode ser usada em conjunto com ferror() é a função perror() (print error). ela ainda especifica o tamanho máximo da string de entrada. ou o disco pode estar com problemas e não conseguimos ler. Por exemplo. ferror e perror Protótipo de ferror: int ferror (FILE *fp). Porém. Como vimos. serão lidos). cujo argumento é uma string que normalmente indica em que parte do programa o problema ocorreu. no máximo. fazemos uso de ferror. onde str e' a string que se está lendo e tamanho deve ser igual ao tamanho alocado para a string subtraído de 1. de modo que consigamos garantir a integridade dos nossos dados. Se o caracter de nova linha ('\n') for lido. ele pode ser lido ou gravado. Na maioria dos casos. char string[100]. No exemplo a seguir. ele fará parte da string.h> int main() { FILE *pf. uma alternativa ao uso de gets é usar a seguinte construção: fgets (str. que está associado ao arquivo de onde a string será lida. além dela poder fazer a leitura a partir de um arquivo de dados e incluir o caracter de nova linha na string. o que não acontecia com gets. ferror() se torna muito útil quando queremos verificar se cada acesso a um arquivo teve sucesso.A função recebe 3 argumentos: a string a ser lida.FILE *fp). A função retorna o número de itens escritos. count indica quantas unidades devem ser lidas. O buffer é a região de memória na qual serão armazenados os dados lidos.int numero_de_bytes. Isto significa que o número total de bytes lidos é: numero_de_bytes*count A função retorna o número de unidades efetivamente lidas. porém escrevendo no arquivo. fputs(string. #include <stdio. pf).int count.h> #include <stdlib. gets(string). . fclose(pf). Este número pode ser menor que count quando o fim do arquivo for encontrado ou ocorrer algum erro. fclose(pf). } fread Podemos escrever e ler blocos de dados. Para tanto. int numero_de_bytes. digite <enter>: "). int count. Seu protótipo é: unsigned fwrite(void *buffer. FILE *fp). O número de bytes é o tamanho da unidade a ser lida.printf("\nNao consigo abrir o arquivo ! "). Para terminar. temos as funções fread() e fwrite(). fread pode ler qualquer tipo de dados. O exemplo abaixo ilustra o uso de fwrite e fread para gravar e posteriormente ler uma variável float em um arquivo binário. pf).FILE *fp). O protótipo de fread() é: unsigned fread (void *buffer. Este valor será igual a count a menos que ocorra algum erro. } } while (strlen(string) > 0). putc('\n'. if(ferror(pf)) { perror("Erro na gravacao"). fwrite A função fwrite() funciona como a sua companheira fread().h> int main() { FILE *pf. exit(1). Quando o arquivo for aberto para dados binários. } do { printf("\nDigite uma nova string. exit(1). 1. Seu protótipo é: int fseek (FILE *fp. } if(fwrite(&pi.bin". fclose(pf).pf) != 1) /* Le em pilido o valor da variável armazenada anteriormente */ printf("Erro na leitura do arquivo").int origem). que retorna o tamanho em bytes da variável ou do tipo de dados.bin". exit(1). "wb")) == NULL) /* Abre arquivo binário para escrita */ { printf("Erro na abertura do arquivo").h> int main() . sizeof(float).sizeof(float). valores possíveis são definidos por macros em stdio. 1. O parâmetro origem determina a partir de onde os numbytes de movimentação serão contados. fclose(pf). "rb")) == NULL) /* Abre o arquivo novamente para leitura */ { printf("Erro na abertura do arquivo"). } Note-se o uso do operador sizeof. if((pf = fopen("arquivo. fseek Para se fazer procuras e acessos randômicos em arquivos usa-se a função fseek(). float pilido. lido do arquivo e': %f". return(0). /* Fecha o arquivo */ if((pf = fopen("arquivo.h e são: Nome SEEK_SET 0 SEEK_CUR 1 SEEK_END 2 Valor Significado Início do arquivo Ponto corrente no arquivo Fim do arquivo Os Tendo-se definido a partir de onde irá se contar.pf) != 1) /* Escreve a variável pi */ printf("Erro na escrita do arquivo"). printf("\nO valor de PI. } if(fread(&pilido.1415. pilido). Exemplo: #include <stdio. exit(1). a partir de um ponto especificado.float pi = 3.h> #include <stdlib.long numbytes. Esta move a posição corrente de leitura ou escrita no arquivo de um valor especificado. numbytes determina quantos bytes de deslocamento serão dados na posição atual. SEEK_SET). printf("Posicao :%i Informacao:%c\n". ou fwrite() e fread(). long pos. int i. Apaga um arquivo especificado.txt". fgets(str. fseek(fp. fp = fopen("arquivo.29. fclose(fp).h> #include <string.h> #include <stdlib. resposta[80]. /* Usa fgets como se fosse gets */ for(i=0. pos = 5. O exercício anterior poderia ser reescrito usando-se. fgets() e fputs(). printf("Posicao :%i Informacao:%c\n". pos = 3. frase[] = "Este e um arquivo chamado: ". e que acrescenta algumas inovações.getc(fp)). /* Le um nome para o arquivo a ser aberto: */ printf("\n\n Entre com um nome para o arquivo:\n").pos. retorna a posição corrente do arquivo para o início.pos. i++) .getc(fp)).{ FILE *fp. char str[30]. A seguir apresentamos uma segunda versão que se usa das funções fgets() e fputs(). remove Protótipo: int remove (char *nome_do_arquivo).pos. str[i].pos."r"). } rewind A função rewind() de protótipo void rewind (FILE *fp).h> int main() { FILE *p.SEEK_CUR). #include <stdio.stdin). por exemplo. fseek(fp. return 0. ..*/ fputs(frase..).79. } 3.char *str. Fluxos padrão Os fluxos padrão em arquivos permitem ao programador ler e escrever em arquivos da maneira padrão com a qual o já líamos e escrevíamos na tela. resposta). p).*/ { /* o programa aborta automaticamente */ printf("Erro! Impossivel abrir o arquivo!\n"). fgets(resposta.p)."w"))) /* Caso ocorra algum erro na abertura do arquivo. fclose(p).4."r").. A diferença é que fscanf() lê de um arquivo e não do teclado do computador. a única diferença do protótipo de fscanf() para o de scanf() é a especificação do arquivo destino através do ponteiro de arquivo. fputs(str.. e o fecha . /* Elimina o \n da string lida */ if (!(p = fopen(str. printf("\n\n%s\n". Como já poderíamos esperar. fclose(p). /* Apaga o arquivo */ return(0).. A diferença é que a saída de fprintf() é um arquivo e não a tela do computador. exit(1). Protótipo: int fscanf (FILE *fp.h> #include <stdlib..). fscanf A função fscanf() funciona como a função scanf().h> int main() .. Fica assim: #include <stdio. a única diferença do protótipo de fprintf() para o de printf() é a especificação do arquivo destino através do ponteiro de arquivo. fprintf A função fprintf() funciona como a função printf(). /* Fecha o arquivo */ remove(str). Talvez a forma mais simples de escrever o programa anterior seja usando fprintf () e fscanf(). /* abre novamente e le */ p = fopen(str..if(str[i]=='\n') str[i]=0. imprime no arquivo. Como já poderíamos esperar.p).char *str. } /* Se nao houve erro. Protótipo: int fprintf (FILE *fp. . /* Le um nome para o arquivo a ser aberto: */ printf("\n\n Entre com um nome para o arquivo:\n"). char str[80]. Introdução Ao contrário do que possa parecer. a redução do espaço físico utilizado é um conjunto de aplicações."r"). ampliando sua capacidade de transferência de informação. fecha . exit(1). comprimir não é somente reduzir o tamanho de um arquivo: há várias outras aplicações que utilizam a compressão de dados. /* abre novamente para a leitura */ p = fopen(str. mas a taxa de transferência de informação estará ampliada para 14400 bps.c).. Obviamente. gets(str). while (!feof(p)) { fscanf(p. Como uma ampliação do número de terminais de uma rede baixa o desempenho. De fato. é possível que ele transmita como se estivesse a 14400 bps? Sim! Basta que ele permita a compressão de dados transmitidos. permite um significativo ganho em termos de ocupação em disco e velocidade de acesso. } fclose(p). if (!(p = fopen(str. A compressão de dados permite."Este e um arquivo chamado:\n%s\n".c. incorporando a compressão no projeto de seus registros. A redução do espaço físico é mais comumente utilizada em bancos de dados que. torna-se necessária ."%c". dado um dispositivo restrito de armazenamento que é um disquete. mas há outro relativo à agilização da trasmissão de dados. Se possuímos um modem que opera a 9600 bps (bits por segundo).*/ { /* o programa aborta automaticamente */ printf("Erro! Impossivel abrir o arquivo!\n"). é a possibilidade de expansão de uma rede de computadores. A compressão também é utilizada para agilizar a transmissão de dados basicamente de duas formas: alterando a taxa de transmissão e permitindo o aumento no número de terminais de uma rede. imprime no arquivo. Compressão de Dados 4. } 4."w"))) /* Caso ocorra algum erro na abertura do arquivo. Outra vantagem da compressão em comunicação. derivada do aumento de velocidade.&c). Na verdade. fclose(p). } /* Se nao houve erro. dado o aumento do tráfego de dados. return(0). str).*/ fprintf(p. printf("%c". esta é aplicação mais comum e mais difundida comercialmente. portanto.{ FILE *p. faz-se evidente a necessidade de muitas vezes realizar-se a redução do tamanho de arquivos para transportá-los ou simplesmente armazená-los.1.. o modem continuará transmitindo a uma taxa de transmissão de 9600 bps. e um grande depositório de arquivos que é um disco rígido. Afinal. o aumento na velocidade de transmissão de dados. Um exemplo clássico é o projeto de um banco de dados utilizando seqüências de bits para a representação de campos de dados. 4. . A característica lógica da compressão encontra-se no fato dos dados já serem comprimidos no momento do armazenamento. No lugar de seqüências de caracteres ou inteiros. utiliza-se bits. duas alternativas: trocar os modems. por exemplo AAAAAAAAAAAA. Há. Como a primeira alternativa é mais cara. O caracter especial é um daqueles caracteres não-imprimíveis que conhecemos no código ASCII.2. 4. um deles indica o caracter (ou conjunto de caracteres) repetido através da substituição por um caracter especial. Tipos de Compressão Compressão Lógica A compressão lógica refere-se ao projeto de representação otimizada de dados.uma transmissão mais rápida de dados. não ocorrendo sua transformação de dados estendidos para comprimidos. a) codificação run-length Quando temos um arquivo onde ocorre uma repetição contínua de determinado caracter. Ambos os tipos de compressão física e suas diversas técnicas serão abordados no decorrer deste capítulo. a partir dos quais é verificada a repetição de caracteres para efetivar a redução do número de elementos de dados. Seleção de Caracteres Indicadores Antes da discussão das técnicas propriamente ditas. utilizando modelos mais velozes. A compressão de dados. Há basicamente 3 formas de representação denominadas run-length . da seguinte forma: Ce 12 A onde A é o caracter repetido 12 vezes. permite a ampliação de uma rede de computadores de uma forma alternativa mais barata. o que é indicado pelo caracter especial Ce . a segunda permite que se alcance o mesmo desempenho com muito menor custo. Existem dois tipos de técnicas para sinalizar a ocorrência de caracteres repetidos: 1. por exemplo. outras técnicas indicam a freqüência de repetição de caracteres e representam isto através de seqüências de bits. neste caso. 2. ou incorporar um chip com algoritmo de compressão aos modens existentes. é necessário o esclarecimento de como são codificados os caracteres especiais a serem substituídos pelos caracteres repetidos neste tipo de compressão física. reduzindo significativamente o espaço de utilização do banco de dados.1. Compressão Física A compressão física é aquela realizada sobre dados existentes. portanto. é possível sua representação através da codificação run-length . Este tipo de compressão é possível de ser efetivada em campos projetados para representar dados constantes.3. códigos e quaisquer outros campos formados por números. run-length estendido e inserção e deleção . como datas. Compressão Orientada a Caracter 4.3. Ora. Y. vazio. Como na língua portuguesa utiliza-se muito pouco as letras K. em geral elas são utilizadas num primeiro nível de compressão multinível. vazio. Pelo contrário.3. A diferença deste para o run-length simples é que há caracteres delimitadores no início e no fim da seqüencia de codificação: SO R A 980 SI onde SO (shift out ) é um caracter especial indicador de início de uma seqüência de caracteres definida pelo usuário até que SI (shift in ) seja encontrado. torna-se necessária a utilização de mais um byte para a representação do valor. ou seja. pode ser comprimida como sendo: .Cabe salientar que esta codificação ocupa somente 3 bytes .. Caso ocorra mais do que isso. de transmissão de dados. Técnicas de Compressão Orientada a Caracter As técnicas de compressão orientadas a caracter não são as mais eficientes ou as mais sofisticadas. por exemplo. b) codificação run-length estendido Como representaremos um número de repetições maior que 256? Utilizando o run-length estendido. Em geral. como representar um inteiro como um byte? Deve-se ter a consciência que em um byte pode ser armazenado um valor de 0 a 255. pode-se.2. O caracter R indica a compressão run-length .. Aqui serão analisados 5 técnicas de compressão orientada a caracter.. pode-se indicar.. Então. Para a compressão. de modo a dar uma noção das possíveis aplicações deste tipo de compressão. onde o caracter A é indicado como repetido 980 vezes.. indicar a compressão de um arquivo de texto na forma: K 12 A 4. Esta é uma propriedade de códigos de caracteres. W. com apenas um byte até 256 ocorrências de caracter. por exemplo. utiliza-se um caracter convencional como indicador de compressão. temos como objetivo comprimir apenas os caracteres nulos ou brancos. por exemplo. utiliza-se a seguinte seleção de caracteres indicadores: Ce N onde Ce é um caracter especial e N é o número (em binário) de caracteres brancos repetidos seqüencialmente.Ce8Exatamente o que. Exatamente o que. são comprimidos caracteres correspondentes ao espaço em branco. Como o valor 980 ultrapassa o limite de 256 de um byte. a) Supressão de Caracteres Nulos Nesta técnica. Desta forma. como o ASCII e EBCDIC. . deve-se utilizar outra representação mais eficiente. uma seqüência do tipo: .. c) codificação por inserção e deleção O que fazer quando não for possível a colocação de caracteres especiais? Há determinados casos que os caracteres especiais utilizados conflitam com outros aplicativos.. onde os demais níveis podem ser técnicas estatísticas de compressão.. volta-se ao passo 2. O algoritmo para a técnica apresentada é muito simples: 1. 5. com visto na seção anterior. se verdadeiro. incrementa-se o contador e verifica-se se o número de caracteres ultrapassou a 255 (limite binário). se for. Desta forma. colocam-se os caracteres indicadores no arquivo comprimido e volta-se ao passo 1. Por exemplo: . 4. será assinalada no mapa de bits. através dos bits. Portanto. 3. valendo a pena comprimir. um por bit do arquivo manipulado. Esta técnica utiliza-se de um byte no arquivo comprimido para indicar. verifica-se se o caracter é um branco. Outras formas de indicação de compressão podem ser utilizadas. se é. verifica-se se o contador é maior que 2. Cada mapa descreve 8 bytes.. inicializa-se um contador para o cálculo do número de repetições de brancos. 2. devemos indicá-lo no mapa de bits. não há a necessidade de explicitação do caracter comprimido.. e volta-se ao passo 1.. lê-se o caracter do arquivo a comprimir. copiam-se os caracteres lidos no arquivo comprimido e volta-se ao passo 1 O fluxograma para o algoritmo apresentado é mostrado a seguir: Figura 10. se não é. será descrito como: . colocam-se os caracteres indicadores no arquivo comprimido. Como trata-se de uma compressão de brancos. para letra encontrada a cada trecho de 8 bytes. abacate . caso desejarmos comprimir todos os caracteres a de um texto. se não for. utiliza-se a compressão por mapeamento de bit.o que demonstra uma redução de 6 bytes no trecho de texto apresentado. caso contrário.. a ocorrência do caractere repetido.Algoritmo de Supressão de Caracteres Nulos b) Mapeamento de Bit Quando é sabida a existência de múltiplas ocorrências não consecutivas de determinado caracter no arquivo a comprimir. portanto. 2. 6. se forem o mesmo. e volta-se para o passo 1. volta-se ao passo 3. Convenciona-se. para o exemplo. valor um em seguida indica um caracter diferente. inicializa-se o contador. troca-se para 1 o bit da posição atual. então grava-se o mapa de bits e os caracteres diferentes do comprimido. 7. Este mapa é composto.. A seguir é apresentado o fluxograma que descreve o algoritmo: . dos bits: onde o primeiro zero indica a presença de um caracter a na primeira posição.. 5. então vai-se para o passo 6... incrementa-se o contador. verifica-se se o contador chegou a 8. 4. e assim por diante.. inicializa-se o mapa de bits colocando todos os bits em zero. Mbbcte. 3. que o bit 0 indica a presença do caracter a comprimir e o bit 1 a sua ausência. compara-se o caracter lido com o caracter procurado. senão. se verdadeiro. O algoritmo para esta técnica necessita do controle do mapa de bits: 1. onde Mb é o mapa de bits correspondente à compressão do caracter a . até completar o mapa. realiza-se a leitura do caracter no arquivo a comprimir. Consiste no seguinte: 1. O fluxograma que permite uma melhor visualização do algoritmo é apresentado a seguir. O algoritmo da técnica comprimento de fileira é simples como os anteriormente analisados. 5. Como podemos perceber. verifica-se se o caracter armazenado é o que procuramos. realiza-se a gravação dos caracteres indicadores no arquivo comprimido e volta-se ao passo 1. faz-se a leitura do caracter no arquivo a comprimir. 7. gravam-se os caracteres lidos no arquivo comprimido e volta-se ao passo 1. esta técnica também permite apenas a compressão de um caracter por vez. buscando a verificação de existência de repetição. se for. incrementa-se o contador de caracteres.c) Comprimento de Fileira Esta técnica aplica a indicação semelhante à run-length de compressão. 4. inicializa-se um contador de caracteres. verifica-se se o contador de repetição é maior ou igual a 4. 2. incrementa-se o contador de repetições. 3. destinado ao controle de cada caracter. 8. C é o caracter repetido e N é o número (binário) de repetições. inicializa-se um contador de repetições do caracter procurado. se for menor. O formato permite a determinação do caracter repetido: Ce C N onde Ce é o caracter especial. 6. o caracter é armazenado e volta-se ao passo 3 para verificação de repetição. se o contador de caracteres for igual a 1. . 4. lê-se o próximo caracter e volta-se ao passo 2. 3. por exemplo. Para a implementação da codificação diatômica segue-se o seguinte algoritmo: 1. numa tabela normal para compactação utilizam-se mais de 20 duplas para que seja obtida uma compressão razoável. Obviamente procura-se substituir os caracteres de maior freqüência. A cada uma dessas seqüência deve-se atribuir um caracter especial para nos permitir a compactação através da codificação diatômica. estes são apenas dois exemplos de duplas de caracteres. coloca-se o caracter especial correspondente no arquivo comprimido e volta-se ao passo 1. se exitente. verifica-se sua existência na tabela de pares. duplas de ocorrência freqüente são a letra a acentuada com til seguido da letra o (ão) e a letra e com acento agudo seguido de um espaço em branco (é ). coloca-se apenas o primeiro caracter no arquivo comprimido. lê-se um par de caracteres. 6. 2. O fluxograma correspondente é o seguinte: e)Substituição de Padrões A substituição de padrões é semelhante à codificação diatômica. desloca-se o segundo caracter para a primeira posição. Normalmente utilizam-se tabelas com pares de caracteres e sua freqüência de ocorrência em determinado tipo de arquivo. . associando a cada dupla um caracter especial. pois também ocorre a substituição de um conjunto de caracteres por um caracter especial.d)Codificação Diatômica Esta técnica de compressão permite a representação de um par de caracteres em apenas um caracter especial. 5. Em texto da língua portuguesa. Obviamente. 1. Por exemplo. substituídas pelos códigos $1 e $2 . é possível calcular a quantidade média de bits por intervalo de símbolo: . utiliza-se esta característica para a sua compressão. a Teoria da Entropia permite a concepção de uma teoria da Harmonia. Aplicada à informação. 4.4. Compressão Estatística A idéia da compressão estatística é realizar uma representação otimizada de caracteres ou grupos de caracteres. com a diferença de que são avaliados um número maior de caracteres. 4. as palavras reservadas begin e end da linguagem Pascal poderiam ser. utiliza-se uma técnica adequada para levantamento estatístico dos dados a comprimir. não necessitamos saber qual caracter vai ser comprimido. A Entropia é a propriedade de distribuição de energia entre os átomos. há troca de energia entre ambos até que atinjam a entropia. sabe-se que estes sistemas estão utilizando o mínimo de energia possível para sua manutenção. o que anteriormente era limitado ao número de caracteres especiais que poderíamos utilizar. A utilização mais comum para este tipo de compressão é a de arquivos de programas de linguagens de programação. e assim se manterão até que outro sistema interaja sobre eles. ou seja. Com base nisso. e os de menor freqüência são representados por códigos proporcionalmente maiores. Teoria da Harmonia Esta Teoria baseia-se no princípio físico da Entropia. o equilíbrio da quantidade de energia exitente nos sistemas. deve tomar como base para a programação o algoritmo e o fluxograma apresentados para aquela técnica. tendendo ao equilíbrio. Desta forma não serão apresentados formas distintas de programação.PALAVRA => Ce O processamento desta técnica é semelhante ao da codificação diatômica. um ponto de equilíbrio onde a informação pode ser representada por uma quantidade mínima de símbolos. são estabelecidas tabelas de palavras de maior freqüência de ocorrência para substituição com o caracter especial. ter o conhecimento da probabilidade de ocorrência de todos os caracteres sujeitos à compressão. a partir da qual teremos uma noção de como se processa a compressão estatística. ou seja. Isso permite a codificação de até 256 palavras reservadas. mas é necessário. permitindo uma compressão considerável de um arquivo de programa. Uma vez que as linguagens contém diversas palavras que se repetem freqüentemente em programas. veremos na seção seguinte a Teoria da Harmonia. por exemplo. Uma variante da substituição de padrões para permitir a codificação de um maior número de palavras é a utilização de dois caracteres para indicação da ocorrência de determinada palavra: CN onde C é um caracter escolhido para indicar a compressão e N é o número (binário) da palavra a substituir. Para chegarmos a esta representação ideal. Ao atingir o estado de equilíbrio. Desta forma. porém. Caso não seja possível a tabulação de todos os caracteres sujeitos à compressão.4. formando tabelas de probabilidades. basta que tenhamos a quantidade de símbolos utilizada e a probabilidade de ocorrência deles. Sempre que um sistema físico possui mais ou menos quantidade de energia que outro sistema físico em contato direto. Para sabermos como foi concebido este tipo de compressão. Caracteres de maior freqüência de utilização são representados por códigos binários pequenos. Neste tipo de compressão portanto. As demais palavras reservadas da linguagem também poderiam ser codificadas desta maneira. Como esta técnica assemelha-se muito à da codificação diatômica. Para a codificação dos próximos caracteres.3. 4. isto implica que.5 0. o que impede a ambigüidade na análise do código. cada qual com uma probabilidade p .1).3 ---------C4 ------.0 -------|-----. A ambigüidade. Duas representações podem ser comparadas para a verificação de qual ocupa menos bits em média.4. ao serem lidos apenas os bits 01.3 = 0. Por isso. existem técnicas que utilizam a análise da probabilidade para compactação de dados. Isso nos permite concluir que é possível a criação de um método de compactação construído a partir da probabilidade de ocorrência de símbolos. De fato.1 para os dois caracteres de menor probabilidade.2. Por exemplo.2 + 0. basta continuarmos a construção da árvore. O próximo caracter será adicionado à árvore: .1 -------A probabilidade do ramo é a soma das probabilidades das folhas (0. Esta representação é gerada por um sistema de decodificação em árvore binária. Foi utilizado um valor n logn por sua proporcionalidade entre quantidade de informação e tempo. seja a seguinte distribuição: C1 C2 C3 C4 0. Estas são chamadas de estatísticas e serão analisadas nas seções seguintes.2 0. utilizada na Teoria da Entropia. A partir dos caracteres de menor valor. de forma que permitam uma decodificação única para cada caracter. determinado caracter C1 tem o código binário 01 e outro caracter C2 tem o código 0100. a fórmula apresentada é semelhante à utilizada para verificação da energia de um sistema físico. Os valores binários serão membros do código formado. a codificação Huffman utiliza o projeto em árvore binária para projeto dos bits que representam os caracteres.2 0.havendo n símbolos. serão atribuídos os valores 0 para C3 e 1 para C4. refere-se a uma decodificação que permite a confusão com outros caracteres. A representação de quantidades em binário é dada pela base 2 do logaritmo. ao verificarmos a seqüência binária para C2 poderemos estar interpretando como C1. Na prática. Codificação Huffman Esta técnica de compressão permite a representação em binário de caracteres a partir de sua probabilidade de ocorrência. Eles formarão um ramo cuja probabilidade será 0. A codificação Huffman necessita de que cada caracter tenha um valor de probabilidade de ocorrência. a fórmula anteriormente apresentada permite-nos verificar se é possível a otimização da quantidade de bits utilizados para representação de determinado conjunto de símbolos.0. representado graficamente desta forma: C3 ------. começa a construção da árvore binária. neste caso. Por exemplo. Por outro lado. Para a codificação.0 -----------------------.0. da raiz para as folhas. Cabe salientar.0. Os valores binários lidos serão o código do percurso da raiz até a folha correspondente ao caracter que se deseja o código.0 |---------------------. não permitindo que os bits da codificação de um caracter confundisse com a de outro. por fim.5 = 0. O objetivo desta numeração é a construção do código binário dos caracteres. Assim acontece com os demais caracteres.5 -----| 1 | |-----. e a codificação da divisão recebeu 0 para uma derivação e 1 para outra.0.0.1 -------- Mais uma vez.3). Uma vez terminada a árvore.2 + 0. A tabela de códigos fica a seguinte: C1 C2 C3 C4 0 10 110 111 Desta forma.3 ------------C4 ------.4. Por outro lado.0 C2 ---------------------. e de um procedimento para a codificação em binário.5 -----| 1 | |-----. baseia-se na divisão de conjuntos de probabilidades para a obtenção do código binário.C2 ---------------------. Necessita-se de uma tabela com a probabilidade de ocorrência de cada caracter. permitindo uma codificação total.0 ------| | 1| C3 ------.----------. em ordem crescente do número de bits. devemos ter os caracteres com suas probabilidades de ocorrência: . uma vez que necessariamente deve-se atingir 100% das ocorrências de caracteres. o procedimento para a codificação. uma vez que permite a substituição do caracter de maior ocorrência por apenas um bit. conforme a prioridade.0 ------| C3 ------. Observe que o caracter de maior freqüência possui o menor valor.3 ------------C4 ------. Codificação Shannon-Fano A forma desta técnica tem muitas semelhanças com a de Huffman. o último caracter é adicionado à árvore: C1 -------------------------------------------------------------------. o ramo é a soma das probabilidades anteriores (0.1 -------- A probabilidade final da árvore é sempre 1.0 -----------------------. basta a formalização da codificação.----------. 4. diferentemente de Huffman. que é feita com a leitura dos valores binários.3. Por fim.1. Isso é exatamente o objetivo da compressão estatística. que a codificação Huffman manteve a propriedade de permitir a decodificação direta. estão codificados os caracteres através da técnica de Huffman.0. 5 0. O primeiro grupo recebe como primeiro valor de código o binário 0 e o segundo recebe 1: C4 C2 C1 C3 0 1 1 1 Como para o primeiro grupo não há ambigüidade em termos apenas um bit.1 0. serão obtidos dois grupos. Para isso.1 0.3 0.3 0. Mais uma vez vamos colocar 0 para distinguir o primeiro e 1 para o segundo: C4 C2 C1 C3 0 1 1 1 _ 0 1 1 Finalmente. um composto pelo caracter C4 e outro pelos demais. vamos resolver o problema do segundo grupo.1 0. dividindo em dois subgrupos de probabilidades equivalentes. repete-se o processo. inserindo o binário 0 na seqüência do código de C1 e 1 para C3: C4 C2 C1 C3 0 1 1 1 _ 0 1 1 _ _ 0 1 .C1 C2 C3 C4 0.1 Uma vez feito isso. divide-se a tabela em dois grupos cuja soma de probabilidades seja igual ou semelhante. No caso da tabela acima. repetimos o procedimento anterior. na base: C4 C2 C1 C3 0. até o menor. O caracter C2 forma o primeiro subgrupo e os demais formam o segundo.5 O passo seguinte é ordenar colocando os caracteres de maior probabilidade no topo da tabela. para resolução da última duplicidade. 4. podemos obter os seguintes códigos: C3 C4 C2 C1 00 01 10 11 O tamanho médio para esta codificação foi: T = 0.2 + 0.1. sendo algumas vezes sendo vantagem usar uma ou outra.3. se não houvessem sido feitas as combinações iniciais em dois grupos.3 + 0.3.3. é possível resultar em: C3 C4 C2 C1 E o tamanho obtido foi de: T = 0.3. e t é o número de bits de código ocupado pelo caracter i . ganhando 0. Mas isso não acontece por acaso.1.1 Codificando por Huffman. 0 10 110 111 .3 0. seja a tabela: C3 C4 C2 C1 0.1 bits Os resultados indicam que a codificação Huffman foi melhor executada.2 + 0.3 = 2. O tamanho médio ocupado por um código gerado pelas técnicas de compressão estatística é dado por: onde N é o número de caracteres da tabela de codificação.1 bit em média. p é a probabilidade de ocorrência do caracter i .2 + 0. basta compararmos o tamanho médio obtido por cada código resultante da aplicação das técnicas. Para decidirmos qual delas é a melhor para determinado caso.4.1 + 0.3 0. Para exemplificar numa comparação entre as técnicas.0 bits E codificando por Shannon-Fano.4. Por outro lado.2 + 0.3 0. A codificação Huffman poderia ter sido pior.3.2 = 2.3. a Shannon-Fano poderia ter sido melhor se fosse escolhido como primeira divisão o intervalo entre C4 e C2. Comparação entre Huffman e Shannon-Fano A geração de código entre as duas técnicas pode ter variações marcantes. Por outro lado.Para melhor ou para pior. portanto. a tabela. A tabela adaptável consiste na mesma tabela que conhecemos. . este será prejudicado na compressão. contendo o caracter o código e a contagem: C1 C2 C3 C4 C5 0 10 110 1110 1111 0 0 0 0 0 caso o caracter C3 ocorra 21 vezes. a codificação continuou a mesma. a necessidade de realizarmos um processamento de leitura e cálculo anterior à compressão propriamente dita. mantendo a coluna de código inalterada. e ordena-se a coluna dos caracteres em ordem crescente a partir desta coluna da contagem. 4. Com a compressão auto-adaptável ganha-se.1 ou 2. Para resolver este caso utiliza-se uma tabela adaptável. o C5 3 vezes e o C4 2 vezes. há a necessidade de se anexar a tabela ao arquivo comprimido. obtém-se uma tabela com os caracteres de ocorrência mais freqüente sendo codificados com menos bits. as técnicas de compressão estatística de Huffman e Shannon-Fano permitem apenas a criação de uma tabela fixa de códigos associados a cada caracter tabelado. Como resultado. uma contagem de quantos caracteres ocorrem no arquivo. o que implica em maior tempo gasto do que com a utilização da tabela fixa. De qualquer forma. em alguns casos. Compressão Fixa x Compressão Auto-adaptável Como vimos. C1 10 vezes.4. o C2 18 vezes. portanto.5. perda da compressão eficientemente obtida. para que os códigos correspondentes possam ser devidamente decodificados. acrescida de mais uma coluna contendo a contagem de ocorrência do caracter no arquivo a comprimir. no exemplo acima ambos poderiam ter dado 2. obviamente. Observamos. Quando comparamos as duas técnicas. geralmente há uma diferença na codificação que nos permite aperfeiçoá-la. contendo o caracter e seu código. uma compressão mais eficiente. a tabela agora será a seguinte: C3 C2 C1 C5 C4 0 10 110 1110 1111 21 18 10 3 2 como vimos. Isso pode significar. então.0. Efetua-se. há um problema pela própria variabilidade da tabela: para a descompressão. Seja. mas a correspondência foi alterada para a situação específica do arquivo comprimido em questão. Caso as probabilidades nas quais foram concebidos os códigos da tabela forem distintos para determinado arquivo a comprimir. é interessante tentarmos a codificação com um ou outro antes de optarmos por uma delas. heap. Para o caso de arquivos alguns fatores devem ser analisados: a) a quantidade de registros a serem classificados b) se todos os registros cabem ou não na memória disponível c) o grau de classificação já existente d) a complexidade e os requisitos de armazenamento do algoritmo a ser usado e) se vai haver inserções e remoções (arquivos dinâmicos) Classificação interna Se o arquivo cabe todo na memória disponível.log n (base 2) (quick. . k. int quaprod.intercala-se a porção já ordenada com outras porções também já ordenadas.)e outros que são proporcionais a n.). pois as operações físicas de entrada/saida em disco. . Entretanto. Uma outra forma é usar-se um método híbrido interno e externo. Algoritmos para classificação externa Da mesma forma que na busca. o melhor é otimizar o número de acessos.coloca-se o que couber na memória disponível e classifica-se b) intercalação . .1. O programa abaixo ordena o arquivo de produtos pelo número de identificação do produto. Outra forma é usar-se um método de 2 fases como o mergesort mostrada abaixo: a) classificação . Para se classificar um tabela na memória existem métodos cujo tempo é proporcional a n (seleção. // classifica o arquivo de produtos pelo número do produto #include <stdio. pois o algoritmo é o mesmo.5. o que deve ser otimizado para a classificação de arquivos é o número de acessos. char nomprod[20]. }. Classificação externa O problema é quando não há memória disponível para o arquivo todo.h> struct produto { int numprod. jmin. Método da seleção Vejamos como fica o método de seleção no arquivo de produtos. .h> #include <stdlib. no caso de arquivos. etc . double preprod. Uma forma é mostrada a frente. Nesse caso pode ser usado um algoritmo de classificação externa como é o caso do método de seleção a seguir. 5. Os métodos de classificação internos nem sempre otimizam a quantidade de acessos a disco. pois não é esse seu objetivo. colocá-lo numa tabela na memória (em geral um vetor de structs) classificá-lo por um bom método de classificação interna (por exemplo quicksort) e gravá-lo novamente classificado. inserção (bubble. Qualquer método que minimize o número de acessos a disco será bom. Claro que o mesmo vale para os arquivos. j. pois nada melhor que ler todo o arquivo. o problema está resolvido. tomam a maior parte do tempo de qualquer algoritmo. shell). deixando na memória apenas a tabela de chaves. . etc . merge. main() { int i. 20s . 1.com/ref/cstdio/ftell.. // para i = 0. // o arquivo tem k registros (0. 1.1. sizeof(struct produto). } .numprod) { // troca o mínimo xmin = x. 1. // posiciona no final do arquivo fseek(fb.%5d . // guarda o registro i e inicia o mínimo com i xi = x. 0. fb). fwrite(&xmin. fb). // compara com o mínimo if (x. FILE *fb. jmin = i. 0). 2).numprod < xmin. fb). while (fread(&x. i++) { // le o registro i fseek(fb.. x. x. . // mostra no vídeo o arquivo gerado // abre arquivo binário para leitura fb = fopen(nomearq. 1. jmin = j. 0). k-1) // vamos classificá-lo pelo método da seleção. * http://www.preprod).. nomearq). jmin*sizeof(struct produto). fread(&x. sizeof(struct produto). sizeof(struct produto). "rb").nomprod. xmin = x. 1. // abre o arquivo binário para leitura e gravação fb = fopen(nomearq. scanf("%s". x. // entra com o nome do arquivo a ser classificado printf("entre o nome do arquivo a classificar:"). x. fb)) printf("\n %5d . } } // grava xi na posição jmin e xmin na posição i fseek(fb. i < k-1. fseek(fb. fwrite(&xi. j < k.html */ // calcula o número de registros do arquivo k = ftell(fb) / sizeof(struct produto). 0). // procura a partir de i+1 for (j = i+1. i*sizeof(struct produto). isto é. . /** * ftell – retorna a posição corrente. j++) { // le o registro j fseek(fb.char nomearq[20].cplusplus. j*sizeof(struct produto).numprod. sizeof(struct produto).2lf". "r+b").%10.. struct produto x. i*sizeof(struct produto).quaprod.%.. xmin. fread(&x. } fclose(fb). xi. fb). sizeof(struct produto). 1. k-2 ache o mínimo e troque com i for (i = 0. 0). Quando o arquivo foi aberto em modo binário o valor obtido * corresponde ao numero de bytes desde o início do arquivo. h> #define num_max_reg 1000 struct produto { int numprod. double preprod. jmin. . O programa abaixo faz a classificação usando o algoritmo descrito. "rb"). nomearqnovo). 1. Claro que só faz sentido se a quantidade de chaves não for maior que a memória disponível para armazenar a tabela. char nomearq[20]. *fnovo. minimizando o número de acessos. // entra com o nome do arquivo a ser gerado printf("entre o nome do arquivo a criar:"). fb)) { tabprod[k] = x.. int tabprod[num_max_reg].. void troca(int *x. A diferença está apenas na quantidade de acessos a disco que é feito por um ou pelo outro.h> #include <stdlib. guardando apenas a identificação do produto // e o número do registro k = 0. Ler o arquivo e colocar na memória a tabela de chaves Uma outra forma de classificar o arquivo.5. }. nomearqnovo[20].numprod. tabreg[k] = k. k-1) fclose(fb). sizeof(struct produto). // entra com o nome do arquivo a ser classificado printf("entre o nome do arquivo a classificar:"). 1.. k++. int *y) { int aux = *x.n acessos a disco (n para ler e n para gravar). *x = *y. } main() { int i. Esse algoritmo terá exatamente 2. // abre o arquivo para leitura fb = fopen(nomearq. . scanf("%s". j. FILE *fb. k. tabreg[num_max_reg]. while (fread(&x. é ler todas as chaves de classificação e colocá-las numa tabela na memória juntamente com o número do registro à qual pertencem. int quaprod. // classifica o arquivo de produtos pelo número do produto // le o arquivo todo e guarda numa tabela na memória só o // número do produto com o registro ao qual ele se refere // ordena a tabela e pronto #include <stdio. scanf("%s". *y = aux. struct produto x. // le todo o arquivo. classificar esta tabela e construir o arquivo ordenado. Esse programa é muito mais rápido que o anterior embora não pareça. } // o arquivo tem k registros (0. nomearq). char nomprod[20].2. j < k. fnovo). for (j = i + 1. } fclose(fb). "wb"). vejamos uma solução com o mergesort.2lf". fread(&x. 1. "rb").20s . i++){ // le registro tabreg[i] e grava na posição corrente do // arquivo novo fseek(fb. while (fread(&x. fnovo)) printf("\n %5d . i++) { // minimo a partir de i jmin = i.%10. &tabreg[jmin]). . j++) if (tabprod[j] < tabprod[jmin]) jmin = j. sizeof(struct produto). } // basta agora criar o arquivo novo varrendo tabreg // abre arquivo original e arquivo novo fb = fopen(nomearq. Dentre estes.3. sizeof(struct produto). Suponha o arquivo de produtos com 8 registros e vamos classificá-lo pelo numprod. fazer o merge dos registros de 1 em 1. x. fwrite(&x. // mostra no vídeo o arquivo gerado // abre arquivo binário para leitura fnovo = fopen(nomearqnovo. 0). } 5. for (i = 0. 1.%. // troca elemento i com jmin troca (&tabprod[i].1. ou seja. troca (&tabreg[i]. Arquivo original 730 156 420 831 525 85 356 654 Criar novo arquivo (arquivo A) contendo os registros ordenados de 2 em 2.numprod. tabreg[i]*sizeof(struct produto). fb).%5d . 1. "rb"). sizeof(struct produto). x. x. fclose(fnovo). &tabprod[jmin]). Mergesort de arquivos A solução de deixar uma tabela de chaves na memória para ordenação ainda tem uma limitação. E quando a memória disponível não é suficiente? Será que há um algoritmo mais eficiente que o primeiro (método da seleção) para ordenar o arquivo? A tentativa imediata é aplicar os algoritmos de classificação de tabelas mais eficientes a arquivos.nomprod.preprod). i < k. i < k .quaprod. x. fnovo = fopen(nomearqnovo.// ordena tabprod permutando também tabreg for (i = 0. Arquivo A 156 730 420 831 85 525 356 654 Criar novo arquivo (arquivo B) contendo os registros ordenados de 4 em 4.8. pois só precisamos de 2 ao mesmo tempo. Arquivo C 85 156 356 420 525 654 730 831 Observe que a cada passo fizemos 2. vamos permutando os arquivos. isto é. ou seja. o arquivo C pode ser o A.log n é bem melhor que n. leitura de 8 registros e gravação dos 8 registros.log 8 (base 2) = 2. Assim o total de acessos foi de 2. Arquivo B 156 420 730 831 85 356 525 654 Criar novo arquivo (arquivo C) contendo os registros ordenados de 8 em 8 (todo o arquivo). O número máximo de passos é de log 8 (base 2). Além disso.n. . Para um n grande 2. isto é. fazer o merge dos registros de 4 em 4. além do original (se é que queremos manter o original). ou seja.n. fazer o merge dos registros de 2 em 2.3 = 48.8 acessos ao disco.8. 4) A cada período (por exemplo a cada 24 horas) faz-se uma consolidação dos 2 arquivos criando um só arquivo ordenado para o período seguinte.4.Terminar.Se não for final de arquivo então retornar ao passo 2. ou então. Isto é. um espaço é aberto e numa operação de remoção um espaço é necessário no meio do arquivo.1. . ser atingido o final do arquivo.Posicionar-se no início do arquivo. Como no caso da busca em arquivos essa solução não é uma solução definitiva. pois numa operação de remoção. 5. apesar de operações de inserção e remoção de registros. Arquivos dinâmicos Em muitos casos os arquivos tem que ser mantidos ordenados. 2 .Se registro atual = registro desejado então Sucesso Terminar 3 . um valor igual ao argumento de pesquisa. São arquivos dinâmicos em geral usados em bancos de dados. 6 . 6. Se não encontrar o registro procurado no original. 2) Marcam-se os registros removidos.5.Fracasso 7 . e com a facilidade de busca da busca binária são as B-árvores. A estrutura que permite que um arquivo permaneça ordenado apesar de inserções e remoções de registros.Se registro atual>registro desejado então Fracasso Terminar 4. até ser localizado aquele que possui.Se registro atual < registro desejado então avançar um registro. Remove-se também os registros não válidos. a partir do primeiro. usando apenas o que aprendemos até agora seria: 1) Mantem-se 2 arquivos o original ordenado e um novo só com os registros inseridos (supondo que não são muitos por período). Neste caso não é possível manter-se o arquivo sequencialmente ordenado. procura no arquivo de novos registros. 3) As operações de consulta verificam primeiro o arquivo original. Pesquisa Sequencial Consiste no exame de cada registro. Passo a Passo : 1 . o que significa que o registro procurado não está presente no arquivo. Métodos de Pesquisa 6. Uma solução intermediária para arquivos dinâmicos. coloca-se um campo a mais em cada registro que diz se o registro é válido ou não. para a chave de acesso. Imagine que cada elemento em um conjunto possua um número associado a ele e que quaisquer dois elementos distintos possuam números associados diferentes. a tabela hash leva em conta somente o seu valor absoluto. b. 2.2. ocorre uma das seguintes situações : a. 6. que a cada comparação é reduzida a metade. remoção e busca em tempo constante.Se registro atual>registro desejado então selecionar metade inferior do arquivo e repetir o processo -passo(2). assumir o comprimento zero. na média levaria 500 comparações. poderíamos armazenar . Ao invés de organizar a tabela segundo o valor relativo de cada chave em relação às demais.Se registro atual<registro desejado então selecionar metade superior do arquivo e repetir o processo .3. Hashing Hashing é uma técnica que busca realizar as operações de inserção. a pesquisa termina com sucesso.Se o conjunto selecionado não possuir elementos então Fracasso Terminar A busca binária faz no máximo 10 comparações para encontrar um registro em um arquivo com 1000 registros. Pesquisa Binária Na pesquisa binária o primeiro registro a ser consultado é aquele que ocupa a posição média do arquivo. Algumas aplicações que são beneficiadas pelo uso de tabelas hash são dicionários e tabelas de palavras reservadas de um compilador. Desta forma. Passo a Passo: 1. Com a pesquisa sequencial levaria no máximo 1000 comparações para encontrar o registro procurado. mais atrativa que a busca sequencial.Posicionar-se no meio do conjunto selecionado. portanto. Caso contrário.Se registro atual=registro desejado então Sucesso Terminar 4. A chave do registro. A busca é encerrada sem sucesso quando a área de pesquisa. A chave do registro é maior do que o argumento de pesquisa e o processo de busca é repetido para metade inferior do arquivo. A busca binária é.passo(2) 5.6. interpretado como um valor numérico. Essa característica é muito importante quando se trabalha com armazenamento secundário em disco. é menor do que o argumento de pesquisa e o processo de busca é repetido para metade superior do arquivo.Selecionar todo o conjunto de registros do arquivo. 3. mas existe um preço a ser pago antes de podermos usar a busca binária: ela só funciona quando a lista de registros está ordenada pela chave que se está usando para realizar a busca. onde o acesso a um determinado endereço é bastante lento. Se a chave do registro for igual ao argumento de pesquisa. 6. é fácil perceber que o processo será muito mais eficiente se a pesquisa for restrita a uma pequena parte do conjunto P (uma única classe). Aplicabilidade Em termos práticos. Ser simples de calcular 2. remoção e busca em tempo constante. Suponha o caso de procurar o nome “Maria” em um conjunto de nomes próprios: Pesquisa sem Hashing .3. Se conseguirmos associar a cada elemento a ser armazenado um número como no exemplo acima. dado um elemento k de um conjunto P. Assegurar que elementos distintos possuam índices distintos. a grande vantagem do hashing está no fato de que. Gerar uma distribuição equilibrada para os elementos dentro do array.os elementos em um array na posição indicada pelo número associado ao elemento. A função que associa a cada elemento de um conjunto U um número que sirva de índice em uma tabela (array) é chamada função hash. fornecendo imediatamente a classe da partição de P em que o elemento se encontra. 6. o valor de hashing h(k) pode ser calculado em tempo constante.1. Uma função hash deve satisfazer as seguintes condições: 1. Se considerarmos P uma coleção de elementos a ser pesquisada. poderemos realizar as operações de inserção. 3. O hashing pode ser usado como uma técnica de redução do espaço de busca. então o valor de hashing calculado dará imediatamente a localização do elemento desejado. sendo este o tipo de busca mais eficiente de que dispomos. neste caso. temos um acesso direto ou randômico como também é chamado. Se o hashing for perfeito. o processo de pesquisa será tão mais eficiente quanto menores forem as partições. . Desde que o código ascii de um caracter é no máximo 127 a função acima assumirá valores entre 0 e 1016. Método da Divisão O método da divisão consiste no seguinte: suponha que os elementos x que devem ser armazenados sejam números inteiros. hashval = (int) a[0]. int Hash(char *a. as chaves são interpretadas como uma seqüência de dígitos escritos num pedaço de papel. Ele consiste em "dobrar" esse papel.6. Principal problema: Elementos distintos podem receber o mesmo índice. uma função hash pode ser obtida somando os valores ascii dos caracteres e procedendo como acima. Funções Hash Criar uma função hash satisfazendo as condições acima nem sempre é uma tarefa fácil. Existem muitos modelos de criação para funções hash. Por exemplo: suponha tablesize = 10. Obs: Utilizar tablesize como sendo um número primo minimiza o problema acima e é uma idéia muito empregada na criação de funções hash. j.2.3. return(hashval % tablesize). por exemplo se tablesize é 10 e os elementos terminam todos em zero. j < stringsize.007 (número primo) e que todas as strings possuam no máximo oito caracteres. Uma dentre as possíveis soluções para esse problema é elevar o valor da soma dos caracteres ascii ao quadrado e só então dividi-lo pelo tamanho da tabela hash. Um dos problemas é que se tablesize é muito grande a função não distribui bem os elementos. A função abaixo descreve a implementação da função hash descrita anteriormente para o caso de strings. não gerando uma distribuição equilibrada. for (j = 1. uma função hash que pode ser utilizada para espalhar tais números em um array (tabela hash) é: h(x) = x % tablesize onde tablesize é o tamanho do array. Para o caso onde o conjunto de elementos é constituído de strings. . /* supondo que tablesize e' global */ } Método da Dobra Neste método. A seguir apresentamos apenas duas formas de criação de funções hash. j++) hashval += (int) a[j]. Uma boa função hash é aquela em que toda entrada (slot) do array possui a mesma probabilidade de ser atingido pela função. int stringsize) { int hashval. de maneira que os dígitos se superponham sem levar em consideração o "vai um" como mostra a figura abaixo. ao invés da soma. pois a tabela hash tem tamanho 16. para compor o endereço-base de uma chave.O processo é repetido até que os dígitos formem um número menor que o tamanho da tabela hash. Nesse caso. Método da Multiplicação Neste método. É importante destacar que o método da dobra também pode ser usado com números binários. Dessa forma. deve-se realizar uma operação de "ou exclusivo". descartam-se os bits excessivos da extrema direita e da extrema esquerda da palavra. Considere que o número de bits necessários para endereçar uma chave na tabela hash seja r. e ter o seu resultado armazenado em uma palavra de memória de s bits. separamos os 4 bits centrais da palavra chave. No exemplo abaixo. a chave pode ser multiplicada por ela mesma ou por uma constante. . pois operações de "e" e de "ou" tendem a produzir endereços-base concentrados no final ou no início da tabela. A técnica descrita acima é conhecida como "meio do quadrado". de matrícula dos alunos de uma universidade: 20020001 20020002 20020003 H(Nro.: Nro. Método da subtração Pode ser usado quando as chaves são consecutivas mas não começam em um. Fold Shift CH = 123456789 123 + 456 789 ____________ 1368 .20020000 Método da Extração de Dígito Neste método dígitos da chave são extraídos e usados como endereços. 3 e 4 do código do funcionário. Matric)= Nro. Matric . Ex. Ex. H(8452) = 84522 = 71436304 = 714 Método Folding 1. Ex. H(547790) = 577 H(856430) = 864 H(523233) = 532 Método quadrático O valor de hash é obtido através do quadrado de algum dos componentes da função.: H(Chv) = extrair dígitos 1.: H(Chv) = Chv2 e extração dos 3 primeiros dígitos. Não apresenta colisões e aplicado em pequenas listas. . se pudermos utilizar diferentes funções hash. Fold Boundary CH = 123456789 123 -> inverter -> 321 456 -> inverter -> 654 789 -> inverter -> 987 ____________ 1962 Pode-se excluir o primeiro dígito para o hash ficar de acordo com o tamanho desejado.. . Seja a = < a0. porém.. O que deve ser pensado e implementado de forma eficiente é a função de transformação que irá . decompomos em caracteres ou substrings). poderão existir números de telefone que possuam os mesmos 3 algarismos finais. m -1. Definimos uma família de funções hashing como: 6. Desta forma. Uma das formas de resolver estas colisões é simplesmente criar uma lista encadeada em cada parte da tabela. 1. o que é muito mais dispendioso computacionalmente utilizamos apenas os 3 algarismos finais. em vez de utilizarmos todo o número para criar sua chave.Pode-se excluir o primeiro dígito para o hash ficar de acordo com o tamanho desejado. Decomponha x em r+1 bytes (para o caso de strings. ar > uma sequência de elementos escolhida randomicamente a partir de 0. teremos em média um espalhamento mais equilibrado. a1. mais de um ou mais dados possuem a mesma chave de pesquisa. A idéia é escolher aleatóriamente (em tempo de execução) uma função hash a partir de um conjunto de funções cuidadosamente desenhado. 2.. ou seja. Assim todos os elementos que tenham a mesma chave farão parte de uma lista que parte da posição da chave na tabela hash que pode ser chamada de área de colisões. algumas funções hash podem espalhar os elementos de forma mais equilibrada que outras. Dependendo da entrada.... Na maioria das funções criadas ocorre o que chamamos de colisão. Hashing Universal Qualquer função hash está sujeita ao problema de criar chaves iguais para elementos distintos. Tratamento de Colisões Se em um determinado Dado temos a informação ( número de telefone ) .. . Uma família de funções pode ser gerada da sequinte forma: Suponha tablesize um número primo.3. Uma estratégia que tenta minimizar o problema de colisões é o hashing universal.3. Com isto a chave será menor. O processo de buscar uma chave que não dê colisões pode ser impossível como vimos anteriormente. Achar uma função chave que se adapte às necessidades de armazenamento ocupando o menor espaço possível e sem colisões pode se tornar uma tarefa memorável. Mas pode ser infinito se: a tabela estiver cheia. No primeiro caso. A função deverá transformar para inteiros as partes dos dados que serão usadas para criar a chave. Este método é eficiente quando espera-se que os elementos fiquem espalhados pelo vetor. typedef struct { int chave.chave != chave && tab[i]. para cada chave de entrada. Rehashing: Uma função de rehash rh recebe o índice de um vetor e produz um outro índice. e que. por exemplo. Se h(chave) já está ocupado com algum registro com chave diferente.criar as chaves para os dados. calcula-se rh(rh(h(chave))) e assim por diante. tornando o próprio método da tabela hash pior do que outros métodos. TipoReg r) { int i.reg = r. } Observar o loop: pára quando acha a chave ou quando acha espaço vazio (CHAVENULA).chave = chave. tab[i]. } return i. Exemplo: h(chave) = chave % 1000. Se a posição rh(h(chave)) estiver ocupada. o elemento que causou uma colisão é movido para a próxima posição disponível. cada uma das chaves resultantes sejam igualmente prováveis de ocorrerem. } Tabela. rh é aplicado ao valor de h(chave) para encontrar o lugar onde o registro pode ser inserido (ou achado). Tabela tab[MAXTAB]. TipoReg reg. int BuscaInsere (int chave. ou se os elementos estiverem muito agrupados. if (tab[i]. rh(i) = (i+1) % 1000. O ideal é que a função de transformação seja simples de ser implementada e alterada.chave == CHAVENULA) { tab[i]. o vetor deve ser ao menos um pouco maior do que o número esperado de elementos. while (tab[i]. ou a função rh for inadequada. i = h(chave). Para tal. as funções de rehash: . Hashing fechado: No hashing fechado. mas perde sua eficácia se o vetor se tornar muito cheio. Nestes casos a procura pela próxima posição livre terá um custo muito alto.chave && CHAVENULA) i = rh(i). Se tívéssemos. podemos usar um contador para indicar se a tabela está cheia. Vantagens e Desvantagens Vantagens Simplicidade É muito fácil de imaginar um algoritmo para implementar hashing. Escalabilidade Podemos adequar o tamanho da tabela de hashing ao n esperado em nossa aplicação. (1/b). rh(i) = (i+c)%MAXTAB.. Neste caso. Aplicação imediata a arquivos Os métodos de hashing.000.4. pois os elementos nessa área deverão ser procurados sequencialmente. Eficiência para n grandes Para trabalharmos com problemas envolvendo n = 1. Quanto mais eficiente o a função menor é a área de dados necessária. onde o hashing será muito melhor do que uma árvore.000 de dados. Hashing em separado : No hashing em separado. podem ser utilizados praticamente sem nenhuma alteração em um ambiente de dados persistentes utilizando arquivos em disco. c e MAXTAB devem ser primos entre si. Tempo médio de acesso é ótimo somente em uma faixa A complexidade linear implica em um crescimento mais rápido em relação a n do que as árvores. ele será procurado na área de colisões. as colisões ocorrentes são movidas para uma área em separado. porém. além de ser mais maleavel para se adaptar a cada novo dado ou necessidade de entrada de dados. determinada por b. Tal método. se o elemento procurado não está na posição esperada. p. tanto de endereçamento aberto como fechado. Desvantagens Dependência da escolha de função de hashing Para que o tempo de acesso médio ideal T(n) = c1 .000 entradas. A situação ideal é quando rh(rh(i)). pode se tornar muito caro se o número de colisões for alto. 6.. Existe uma faixa de valores de n. e que não é acessado pela função hash (nenhum elemento que não colidiu irá para essa área). É um processo rápido.ex. onde temos uma divisão do espaço de busca da ordem de n/2. cobre o maior número de inteiros entre 0 e MAXTAB-1.000 de imediato.3. O vetor deve possuir um espaço para armazenar as colisões. simples e eficaz. haveriam muitas colisões e o loop poderia ser infinito mesmo havendo ainda espaço na tabela. Por exemplo. pois. é necessário que a função de hashing divida o universo dos dados de entrada em b conjuntos de tamanho aproximadamente igual. Fora dessa faixa é pior. além de deixar o vetor em si relativamente vazio.n + c2 seja mantido. podemos imaginar uma tabela de hashing com 2. geralmente no fim do vetor. rh(i) = (i+200) % 1000.rh(i) = (i+2) % 1000. . Índice Invertido À medida em que os robots4 vão rastreando a web. Suponhamos que os bots tenham encontrado e armazenado uma página que tenha o seguinte corpo: Estudo de Ferramentas de Busca Um tipo de site está se tornando mais e mais popular na internet: as ferramentas de busca. tornar possível) o trabalho de pesquisa. a Google. Cada página recebe um identificador. para se analisar o conteúdo de uma página. As ferramentas ou máquinas de busca ajudam usuários a encontrar aquilo que procuram. as páginas encontradas vão sendo armazenadas nos discos rígidos das Search Engines.br A primeira coisa a fazer é atribuir um identificador para o documento. Para facilitar (ou melhor. palavras comuns em português não são filtradas. já que. torna-se difícil a pesquisa por [palavras-chave].com. a SE já tem um banco de dados contendo páginas da web. que não são indexados. armazená-las e extrair os links existentes.br 4 Aplicativos que têm a função de recuperar páginas da web. o próximo passo no trabalho das SEs é criar um índice. nesse formato de armazenamento. "e". inverted index). docID=E29A. Altavista. entretanto.1. é necessário recuperá-la. como "of". Nota: a Google filtra os termos comuns em inglês (que ela chama de "stop words"). O ajuste seguinte é nas palavras que sobram: todas as palavras têm seus acentos removidos e a caixa é convertida para letra minúscula. "to". como o Google. por exemplo. . mas suporemos no exemplo que elas sejam. Para demonstrar sua utilidade os exemplos e comentários das próximas páginas fazem referência aos maiores consumidores deste tipo de tecnologia. todos os acentos e sinais de pontuação são eliminados do texto. etc. interpretá-las. são filtrados os termos muito comuns. os chamados Search Engines (máquinas de busca). que o termo foi filtrado. Além disso. Mas essas teorias podem ser implementadas em sistemas de qualquer porte. por exemplo. chamado índice invertido (em inglês. 7. como "de". mas todo o texto é armazenado. qualquer referência à página é feita por meio do identificador.rankings. Também conhecidos como crawlers. Primeiramente. Nesse estágio. o texto ajustado ficaria: estudo ferramentas busca tipo site esta tornando mais mais popular internet ferramentas busca ferramentas maquinas busca ajudam usuarios encontrar aquilo procuram para obter outras informacoes acesse www. denominou esse identificador docID (identificador de documento). A seguir.rankings. ler seu conteúdo e armazená-la novamente. A melhor maneira de se entender o processo de indexação é através de um exemplo simples. etc e informa. Algoritmos para indexação Neste capítulo são apresentados algoritmos de indexação.7. Isso explica por que pesquisas por [Máquinas de Busca] e [maquinas de busca] geram o mesmo resultado na Google. são feitos alguns ajustes no texto. Assim. "um". úteis na utilização em sistemas com grandes quantidades de informações a serem pesquisadas. Para obter outras informações. etc. acesse www.com. na página de respostas. bots ou spiders. as páginas passam por um processo de compressão. . ferramentas (wordID=#0002).. os documentos comuns a todas as pesquisas conterão todas as palavras (mas não necessariamente na ordem pesquisada). O conjunto de palavras compõe o que a Google denominou Lexicon... 18) (. (E29A. para cada palavra (ou seja. num outro documento de docID="390A". a palavra "ferramentas" ocorra na posição 310 do texto. por conta dos termos que aparecem repetidos. teve três hits registrados. como "or" e . tipo (wordID=#0004). observe também que a palavra "usuários".. busca (wordID=#0003). (E29A.10 de aproximadamente 61.000 para [brasil]). já se poderia implementar alguns operadores booleanos. recebeu wordID="0013". 12). 310) (.. O registro correspondente a essa palavra seria modificado para refletir a ocorrência desse hit. apesar de estar na 18a. e os hits correspondentes passam a ser registrados.000. (E29A. 2). é possível saber em quantos documentos ela ocorre (é dessa forma que a Google informa "Resultados 1 .) #0013 (..) Hits (E29A. Também através de refinamentos das páginas retornadas para cada palavra. Suponhamos que.. já seria possível fazer uma Search Engine extremamente rudimentar. os documentos (docIDs) em que elas ocorreram. 12). O processo acima é repetido para todos os documentos armazenados pela Search Engine... seriam criadas as wordIDs: estudo (wordID=#0001). No nosso exemplo. as utilidades do índice invertido já começam a se tornar evidentes: para cada palavra pesquisada. Assim. 2). bem como detalhes da apresentação da palavra.1. 14).. e em qual posição do texto elas se encontram. chamado pela Google wordID. Se no documento seguinte uma palavra nova é encontrada. (390A.1.) (E29A. (E29A.. ela recebe uma wordID. 3) (E29A. cada wordID). wordID=#0002. 4) (.) Hits (. e assim por diante. 7. poderíamos armazenar apenas os Hits (os docIDs em que a palavra ocorreu) e a posição da palavra no texto..) (E29A.. A ocorrência de uma wordID em um documento é chamada Hit. e para todas as palavras (excluídas as stop words) encontradas. são necessárias duas ou mais pesquisas ao índice invertido.. a segunda ocorrência da palavra ferramentas não causa a criação de uma nova wordID. Para o caso em que a pesquisa contém duas ou mais palavras. ficando da seguinte forma: wordID (. assim. 1) (E29A.Cada palavra remanescente recebe um identificador. 14) (E29A. O índice invertido é um banco de dados que armazena.) Observe que a a palavra "ferramentas". é adicionada ao Lexicon. Observe cada palavra recebe um único wordID.) #0002 (. Utilidades do Índice Invertido Mesmo nesse modelo bastante simplificado. posição. Num exemplo bem simplificado. o início de nosso índice invertido ficaria assim: wordID #0001 #0002 #0003 #0004 (.) O índice invertido está completo após o registro da última palavra do último documento.. o Google utiliza o PageRank para classificar os resultados. sempre usando o docID como chave primária). 0). o docID é o mesmo nos dois índices). Nesse modelo básico. pode-se criar um campo para indicar que determinada palavra foi escrita em negrito ou itálico e. para relacionamento dos índices (ou seja. Para aumentar as potencialidades do índice invertido. ocorrência de palavras em locais estratégicos das páginas. para agregar informações que considerem relevantes para formação dos rankings. Este valor é armazenado no índice. 310.. Aprimorando o índice Na seção anterior. como citado acima. (E29A. o valor do respectivo PageRank (na verdade. 14. o docID é a chave primária.. os autores (Larry Page e Sergey Brin) fazem distinção entre "fancy hits" (que ocorrem apenas no título e nos links) e "plain hits" (que ocorrem em todo o restante do texto). como título (texto entre [title] e [/title]) e nos textos-âncoras dos links.) Hits (.2. as Search Engines armazenam muito mais informações. 12. etc). o registro dessa palavra (wordID=#0002) ficaria: wordID (. assim. (E29A. A Google considera esses dois últimos itens (palavras-chave no título e nos textos-âncora) tão importantes. armazenamos tão somente os documentos (docIDs) em que ocorrem e as respectivas posições no texto. (390A. De fato. 1). para cada palavra do Lexicon. a quantia de espaço necessário para armazenar o Lexicon pode representar uma fração substancial do espaço ocupado pelos próprios documentos. A principal vantagem dos arquivos de assinatura é que eles não necessitam que um Lexicon seja mantido em memória durante o processamento das pesquisas. portanto. o Lexicon não é mais necessário. que criou índices específicos para registrá-los. h2. para cada página. Se o vocabulário de palavras criado a partir dos documentos armazenados for rico.) (E29A. Por exemplo. Por exemplo.. lembrando que palavras adjacentes têm posições de hits consecutivas. a Google armazena. vimos um modelo básico de índice invertido. do algoritmo de ordenamento). 0) (. 0). Esses índices são os pesquisados quando usuários fazem consultas com os comandos "allinanchor:keyword" e "allintitle:keyword". . a primeira ocorrência da palavra "ferramentas" está em negrito..1. 7. e seu cálculo será explicado na próxima seção. 7. 2. No paper original da Google (The Anatomy of a Large-Scale Hypertextual Web Search Engine). o índice invertido pode tornar-se muito mais úti. Assim. Arquivos de Assinatura Uma alternativa para a técnica de índices invertidos é a utilização de arquivos de assinatura (signature files). teria mais destaque do que o restante do texto (o campo armazenaria o valor "1" para palavras em negrito ou itálico.2. e "0" para as demais").. exemplos: ocorrência de palavras em cabeçalhos HTML (h1. tamanho das fontes. as Search Engines adicionam outros campos a seus índices. um outro índice armazena o PageRank. os índices armazenam basicamente dois tipos de dados: as páginas que foram descobertas (trabalho dos bots) os elementos que as SEs considerem relevantes para formação dos rankings (ou seja.. Após utilizar a técnica de índice invertido para localizar os documentos que contém os termos pesquisados. com esta técnica.) #0002 (. No exemplo anterior.) De maneira análoga... e as restantes em texto normal."not". Para se encontrar as páginas em que as palavras-chave apareçam na ordem em que foram digitadas. basta fazer uma análise adicional das páginas retornadas para cada palavra. com alguns aprimoramentos. Entretanto. cuja assinatura é 1010 1000 0000 0000 podemos identficar que o termo pode ocorrer nos documentos 2 (1110 1111 0110 0001). portanto. porque alguma combinação das assinaturas de outros termos podem ter mudado o valor da assinatura para 1. Analisando-se as assinaturas dos documentos verificamos que a palavra it pode ocorrer somente nos documentos 4 e 5. é preciso verificar se todos os bits que possuem valor 1 na assinatura do termo estão com o mesmo valor na assinatura do documento. Estes assinalamentos são feitos usando-se a técnica de hashing. some like it cold. se o termo de consulta T for a palavra it. o que de fato ocorre. Caso contrário T provavelmente ocorre neste documento. A assinatura do documento é formada pela assinatura de todos os termos contidos nele. T não aparece no documento. a assinatura dos documentos serão: Documento Pease porridge in the pot. não pode-se dizer com certeza se T aparece ou não no documento. Some like it in the pot. Cada termo em um documento é assinalado para uma assinatura randômica. Assinatura 1100 1111 0010 0101 1110 1111 0110 0001 1010 1100 0100 1100 1100 1110 1010 0111 1110 1111 1110 0011 1010 1100 0100 1100 Assinatura Para verificar se um termo T ocorre em um documento. Para gerar a assinatura de um documento simplesmente realizamos a operação lógica OR na assinatura dos termos do documento. 3 (1010 1100 0100 1100).Arquivos de assinatura são um método probabilístico para indexar documentos. pease porridge cold. Já se pesquisarmos pela palavra the. Por exemplo. Nine days old. cuja assinatura é 0000 1000 1000 0010. 5(1110 1111 1110 . na forma de um vetor de bits. Texto Pease porridge hot. Some like it hot. Se não. cujas assinaturas respectivamente são: 1100 1110 1010 0111 e 1110 1111 1110 0011 . consideremos a lista de termos de um texto e suas assinaturas correspondentes: Termo cold days hot in it like nine old pease porridge pot some the 1000 0000 0010 0100 0010 0100 0000 1000 0000 1010 0000 0000 0000 1001 0010 0000 0000 1000 1000 0010 0100 0010 0000 0001 0010 1000 0000 0100 1000 1000 0100 0000 0000 0101 0000 0001 0100 0100 0010 0000 0000 0010 0110 0000 0100 0100 0000 0001 1010 1000 0000 0000 Se os documentos são compostos por frases usando estes termos. Por exemplo. Nine days old. Basicamente.1. ou nenhum efeito. utilizando uma vasta estrutura de links como indicador do volume individual de uma página. o PageRank de uma página web é calculada como a soma dos PageRanks de todas as páginas ligadas a ela (seus incoming links). o Google interpreta um link de uma página A para uma página B como um voto. palavras comuns podem ser representadas pelo código binário menor. A velocidade de retorno que você experimenta pode ser atribuída em parte à eficiência do algoritmo de pesquisa e em parte aos milhares de PC's conectados formando um super rápido search engine. o Google combina o PageRank com um sistema sofisticado de localização de texto para encontrar as páginas que são importantes e relevantes para a pesquisa. um sistema de ranqueamento de páginas da web desenvolvido pelos fundadores Larry Page e Sergey Brin na Universidade de Standford. O algoritmo PageRank é elegantemente simples e calculado como segue: PR(A) = (1-d) + d (PR(T1)/C(T1) + . neste caso. Claro que páginas importantes não têm significado se elas não responderem a sua pesquisa.. para acelerar as pesquisas. Assim. ou um link que a página recebe. O Google vai muito além do número de vezes que uma expressão retorna em uma pesquisa. O coração do software é o PageRank. O número de outgoing links na página que aponta para a página calculada.85 Desta forma. O PageRank baseia-se na natureza democrática e única da web. Por exemplo. o Google examina todos os aspectos do conteúdo da página (e do conteúdo da página a que ela se refere) para determinar que a expressão é realmente relevante para sua pesquisa. a probabilidade de ocorrerem falsos positivos. + PR(Tn)/C(Tn)) onde PR(A) é o PageRank da página A PR(T1) é o PageRank da página T1 C(T1) é o número de links saindo (outgoing links) da página T1 apontando para outras páginas da rede d é um valor variando de 0 a 1 ( 0 < d < 1) indicando a nota que o Google dá à página de acordo com sua importância. dividido pelo número de links em cada uma destas páginas (seus outgoing links). Por exemplo. uma com 5 outgoing links e outra com 10.3. Páginas classificadas de "Importantes" e sites de alta qualidade recebem um PageRank maior. mas de fato ele ocorre somente no segundo e no quinto. que o Google memoriza toda vez que conduz uma pesquisa. Esta técnica pode ser aprimorada para tratar palavras que aparecem com maior frequência em diferentes buscas. Esta é a principal desvantagem deste algoritmo. dadas duas páginas com igual valor de PageRank ligadas a página calculada. A próxima coisa que pode-se obervar sobre o algoritmo PageRank é que ele não possui relação . sendo geralmente usado 0. o Google analisa também a página que dá o voto.. Então. Votos dados por páginas que em si são "importantes" têm maior peso e auxiliam a fazer outras páginas "importantes".3. a primeira irá aumentar o valor do PageRank duas vezes mais que a segunda. no resultado. pois nenhuma página “apontando” para a página calculada irá ter um efeito negativo. em seu paper The Anatomy of a Large-Scale Hypertextual Web Search Engine. 7. facilitando sua pesquisa. mas em compensação não ocorrem falsos negativos. quanto menos melhor.0011) e 6(1010 1100 0100 1100). Algoritmo PageRank O Google roda uma combinação única e avançada de sistemas de hardware e software. Algoritmos de Ranking 7. existem duas maneiras que podem afetar o valor do PageRank: O número de incoming links: quanto mais melhor. Para uma página conseguir um alto PageRank.. Kleinberg estava desenvolvendo um trabalho chamado Authoritative Sources in a Hyperlinked Environment (fontes que sejam autoridade em ambientes de hiperlinks). a patente da HITs foi adquirida pela Teoma. Assim. Na Seção 6. sem se importar com o tópico das mesmas. Talvez uma boa maneira de olhar para o PageRank é como um fator de multiplicação. Deficiências do PageRank Apesar de ter colocado a Google em vantagem em relação às demais Search Engines. para aumentar seu PageRank. Sergei e Larry escreveram: "Esses tipos de PageRank personalizados são virtualmente imunes a manipulações movidas por interesses comerciais. pode-se dizer que a Google foi vítima do seu próprio sucesso. ela deve convencer uma página importante. A título de curiosidade: por volta da mesma época em que Page imaginou o PageRank. e entáo multiplica esta relevância pelo valor do PageRank para produzir uma lista final.1. ou uma porção de páginas sem importância.1 do documento original sobre PageRank. para cada pesquisa. e muito importante. a maneira mais fácil era obter links em outras páginas de alto PageRank. As pessoas aproveitaram-se da deficiência do PageRank acima mencionada para manipularem seus rankings.3. Mas isso parece estar sob controle. que recebeu o nome HITS. independente do conteúdo das mesmas. já que custa dinheiro. O algoritmo Google primeiro calcula a relevância das páginas em seu índice em relação com os termos da pesquisa. não foi adiante porque não havia recursos tecnológicos suficientes para torná-lo comercialmente viável." Eles estavam errados. todos queriam ter bons rankings na Google. na verdade. No pior caso. 7. o algoritmo de Kleinberg considerava apenas os links contidos em páginas cujo tópico fosse similar ao da página sob análise. o projeto. Em primeiro lugar. ficou evidente que havia grande correlação entre o posicionamento de uma página no ranking e seu PageRank. outro pesquisador chamado J. uma pessoa procurando aumentar seu PageRank tinha apenas que conseguir links em outras páginas de alto PR.com a relevância dos termos pesquisados. Com o tempo. a diferença era que. Quanto maior o PageRank de uma página. que também analisava a estrutura de links para atribuir índices de relevância a cada página. O problema dessa técnica é que o grafo a ser analisado depende da [palavra-chave]. Entretanto. a compra de espaço publicitário (links de texto ou banners) era comum. quer o link apontasse para um site sobre filmes dos anos 50 na Chechênia. Ele simplesmente é uma pequena. parte dos algoritmos usados pelo Google.. poderemos ter manipulação na forma de compra de publicidade (links) em sites importantes. Antes da Google. para calcular o "PageRank" de uma página. quer o link apontasse para um site sobre astronáutica (tópico correlato ao da página da NASA). Após seu explosivo crescimento. Isso significa que um link da homepage da NASA transferia a mesma quantidade de PageRank. a linkar para ela. deve-se mencionar que o algoritmo tinha uma deficiência desde a origem: o PageRank era passado de página a página. ninguém se importava com PageRank. o algoritmo do PageRank tem algumas deficiências. e portanto deve ser montado em tempo real.1. mais e mais pessoas aprenderam que. . mas o principal objetivo do comprador era conseguir tráfego. alguns anos depois. melhor será sua posição na lista de resultados. aplicado aos resultados da busca após outras computações terem sido completadas. O algoritmo Hilltop atacou esses dois problemas. A seguir. são indícios de que o Hilltop (ou boa parte dele) foi incorporado ao algoritmo da Google. o posicionamento de uma página reflete a opinião coletiva dos melhores experts independentes naquele tópico.páginas que tenham sido criadas com o propósito específico de encaminhar as pessoas aos recursos que procuram. Esse site atingiu PR7 em sua homepage. por um preço muito maior. PageRank virou uma commodity. que os links agora não são mais todos iguais. O algoritmo Hilltop Uma das deficiências do algoritmo de PageRank é que qualquer link. apontar links de suas próprias páginas e conseguir um bom posicionamento inicial. Webmasters compravam links interessados apenas no PageRank. 7. aumentava o PageRank (e melhorava o ranking) da página que recebia o link. nós primeiro computamos uma lista dos maiores experts naquele tópico. 2) uma vez tendo construído um site de alto Pagerank. vendendo PageRank. ao longo dos anos.mas não ganhou. de acordo com o número e a relevância de experts não-afiliados que apontam para elas. e de que os resultados da Google hoje reflitam muitos dos conceitos expostos no paper. publicaram informações úteis e relevantes. na seção 1. É bem verdade que muitos (a maioria) dos grandes sites não se envolveu nesse comércio de PageRank. dois problemas maiores preocupavam a Google: 1) webmasters estavam comprando links. A Google alterou o PR da SearchKing. Outros sites que se beneficiaram foram aqueles que. quando era pesquisador da Compaq. e abertamente anunciava a venda de links.edus. Por exemplo. alguns grupos de sites rapidamente aderiram ao comércio de PageRank. Entre vários outros.2. as grandes corporações continuaram sua vida normalmente." Veja-se. Os links. A SearchKing iniciou um processo judicial contra a Google . . os fatos de que Bharat seja hoje pesquisador sênior da Google.3. ficava fácil para os webmasters construírem outros sites e. Não há informações oficiais de que o Hilltop tenha sido implementado. Entretanto. Hilltop não retornará resultados. muitas pessoas que nunca pensaram em ter qualquer retorno financeiro de seus sites informativos agora podiam faturar um bom dinheiro. que o número e qualidade das fontes que fazem referência a uma página dão uma boa medida da qualidade da mesma. Dessa forma. A diferença chave consiste no fato de que nós consideramos apenas fontes que sejam "experts" . Quando um conjunto de experts não existir.com. como forma de se conseguir PageRank e melhores rankings. nós identificamos links relevantes dentro desse conjunto de experts. O próprio autor descreve a base do Hilltop.2 do paper: "Nossa técnica é fundamentada nas mesmas suposições dos outros algoritmos baseados em conectividade. Essas páginas alvo são então rankeadas. pois. Para responder a uma pesquisa. e não na quantidade ou qualidade do tráfego que receberiam. e os seguimos para identificar páginas alvo. que deveriam funcionar como meio de acesso a outras fontes interessantes de informação (esse era o espírito original do PageRank) passaram a ser objeto de compra e venda. em qualquer página contida no índice. Hilltop é focado na relevância dos resultados.com. agora podiam inserir mais links em mais páginas. Entretanto.Em pouco tempo. tinha excelentes rankings. que viu seu tráfego encolher. Leia o paper original sobre o algoritmo Hilltop. para aumentar seu PageRank. um exemplo desse tipo de site é foxnews. O Hilltop foi concebido por Krishna Bharat. e subitamente viram-se detentores de uma mercadoria relevante chamada PageRank (vários sites na geocities enquadram-se aqui). em inglês. Um caso que ficou notório foi o da searchking. Assim. de imediato.govs. Os . alguns grandes sites de alto PageRank que desde sempre venderam links. . ou seja. e não na abrangência da pesquisa. conquistaram merecidamente vários links. Como construir o vetor de termos de uma dada página? Segundo o trabalho de Bharat. que . vetor pode ser grosseiramente definido como uma coleção de elementos semelhantes. tem também interesse por esse tópico. Lei Áurea). pois palavras raras não permitem uma boa avaliação de similaridade de páginas.Clique Aqui" poderia ter uma pontuação menor do que outra que exibisse o texto "Imóveis apartamentos compra venda barato apartamentos imóveis casas especialista . e podem ser aplicados aos vetores de termos. Por exemplo. Bharat foi co-autor de um paper. uma análise semântica permitiria. constrói-se um léxico. uma empresa focada exatamente na aplicação de estudos semânticos à recuperação de dados na web. Leia mais adiante a seção sobre Aplicações da técnica.7. Simplificadamente. o correspondente vetor de termos é um retrato das palavras que descrevem a página. assim como as palavras menos utilizadas. por exemplo. elas não costumavam fazer análises semânticas. vocábulos) que compõem um texto". No trabalho de Bharat. chamado The Term Vector Database: fast access to indexing terms for Web pages. esse conjunto de palavras é um vetor de termos simplificado. pois palavras que aparecem em muitos vetores não permitem diferenciação entre eles (no caso extremo. uma coleção de palavras (representadas por números binários).3. muito embora esta seja claramente uma tentativa de se manipular os rankings por meio de repetição de palavras-chave. para cada URI. há sinais de que a Google (assim como outras SEs) esteja implementando técnicas de análise semântica. uma página que contivesse unicamente o texto e link "Essa página traz informações relevantes sobre a compra e venda de imóveis . Análise semântica Embora as Search Engines indexem cada uma das palavras presentes em um texto. ou seja. a Google adquiriu a Applied Semantics. O objetivo é criar um banco de dados que. para cada página). foram expurgadas as palavras mais utilizadas. 7.3. Para cada URI (ou seja. não por coincidência. Brasil. Escravidão. Outro indício de que a Google tem incorporado análise semântica ao algo é que Krishna Bharat. ou seja. hoje pesquisador sênior da Google. Esse tipo de classificação pode ser expandido. Em termos matemáticos. utilizando-se recursos atuais de tratamento e recuperação de informações.Clique Aqui". o léxico consistia das palavras no "terço intermediário" do índice da Altavista. enquanto aquela pareça ser uma fonte mais confiável de informações. uma palavra que aparecesse em todos os vetores seria inútil para identificá-los). Há alguns anos. apresentado na 9a. Um vetor de termos é. Para combater esse tipo de distorções. não procuravam interpretar o significado do conjunto de palavras. vários teoremas tratam de vetores. a técnica adotada foi a seguinte: Primeiramente. A ausência de análise semântica favoreceu também a manipulação de PageRank: a compra e venda de PR tornou-se difundida porque o PR é (ou era) transmitido independentemente dos tópicos das páginas que trocavam links. um conjunto de todos os termos que são passíveis de serem reconhecidos e catalogados. principal responsável pela concepção do algoritmo Hilltop. que se fulcra exatamente na análise do contexto semântico de uma página para escolher um anúncio que seja relacionado com o tema da página. o vetor pode conter muito mais termos. por exemplo. páginas de contextos semânticos completamente diferentes). Term Vector Database Term Vector Database = Banco de Dados de Vetores de Termos. Conferência WWW em 2000. a palavra "termos" tem o mesmo sentido que em "termos (palavras. pois. a idéia é reproduzir o trabalho feito há tempos para classificar livros em uma biblioteca: uma obra sobre "Antecedentes da Lei Áurea" pode ser representada por um conjunto de palavras como (História. armazene um vetor de termos.3. pouco tempo após a aquisição da Applied Semantics a Google lançou o Adsense. detectar casos em que uma página sobre educação infantil de PR7 contivesse um link para uma página de cassinos (ou seja.1.3. todos os vetores têm o mesmo comprimento do vetor-mãe.1] página B = [1.0.0. como título. como determinar quais páginas são correlatas.0.1. Classificação de Páginas : Como classificar..0. Topic Distillation é uma tentativa de mitigar uma das deficiências do algoritmo de PageRank: em vez de fazer uma análise genérica de conectividade (como ocorre no cálculo de PR).0. é bem sabido (por matemáticos) que o valor do produto escalar de dois vetores fornece uma indicação da semelhança entre eles.g. o primeiro indicando a ocorrência. construir um vetor de termos específico.0.1. Por exemplo. o segundo o seu peso. cria-se um vetor-mãe. 7. daí a necessidade de se ter os vetores pré-computados armazenados em um banco de dados.1] página C = [0. Nota: Bharat afirma que é inviável criar vetores de termos em tempo real (provavelmente. Topic Distillation : Bharat afirma que o trabalho sobre Vetores de Termos foi desenvolvido com a finalidade se aprimorar o algoritmo de Topic Distillation (algo como seleção de tópicos).0] Fica fácil (para seres humanos) observar que o grau de semelhança semântica entre as páginas A e B é muito maior do que entre qualquer uma delas e a página C.1.1. O trabalho de Bharat menciona duas aplicações do vetor de termos: Topic Distillation e Classificação de Páginas.0.1]. O trabalho de Bharat foi um pouco mais adiante: para cada termo.0.1. o peso pode ser maior para termos aparecendo em pontos-chave. Bharat definiu o peso simplesmente como o número de ocorrências do termo na página.1. realizando cálculos com os vetores. Definido o léxico. o vetormãe.1.1.. o elemento do vetor será 0 ou 1.0.1.1.era o objetivo do trabalho. em um exemplo simplificado: página A = [1.0.. por definição.1.1. conforme o termo existente no léxico ocorra ou não na página.. da mesma ordem que o número de termos existentes no léxico. mas admite que definições mais complexas (e. texto em negrito..0.0. Torna-se possível. se o primeiro elemento do vetor-mãe corresponder ao termo "pesquisa". é [1.0. Bharat criou doze vetores a partir da indexação das doze . O problema era. o vetor de termos é uma solução para o problema.1. Aplicações do Vetor de Termos A principal utilidade dos vetores de termos é mensurar similaridade entre páginas web.0. mas podem fazer cálculos com os vetores. e a seguir comparar cada página com esse vetor-do-tópico.0.3. em que a quantidade de 1s é igual ao número de termos do léxico. Computadores não podem visualizar semelhanças e diferenças. Cada posição no vetor representa a ocorrência de determinado texto em uma página. o grande gargalo seria o tempo necessário para baixar a página).1. automaticamente.0. páginas da web em tópicos? Uma solução possível é criar um vetor que represente os termos usados com mais freqüência em páginas do tópico. os engenheiros da Google conseguem avaliar o grau de semelhança entre duas páginas. Por exemplo.0. etc). Como criar um vetor-detópico? Basta rastrear um conjunto de páginas que se saiba.1. e indexar as palavras encontradas.2. já é intuitivo que a semelhança de vetores indica uma semelhança entre os tópicos de duas páginas. Isso significa que cada elemento do vetor é um par de números.0. o algoritmo de Topic Distillation levaria em conta apenas links existentes em páginas correlatas. Consideremos esses três vetores.0. por exemplo. âncoras. de antemão. Embora os vetores provavelmente passem por uma análise matemática depurada.0. tenham foco naquele tópico.. não apenas sua ocorrência foi vetorizada. justamente.1.1. para cada página.0.3.1.0.1. todas as páginas que contiverem o termo "pesquisa" terão o primeiro elemento do seu vetor de termos definido como "1". mas também foi-lhe atribuído um peso. mais CPU) podem ter tornado possível a implementação de algoritmos antes impraticáveis (as atualizações do índice. mais memória. Outras aplicações: O trabalho de Bharat foi apresentado em 2000. a página é classificada na categoria em que houver maior semelhança de vetores. . desde então. Outras aplicações são possíveis. é importante observar que os avanços tecnológicos (mais máquinas. e outras técnicas de análise semântica. tornaram-se praticamente diárias).categorias do diretório do Yahoo! Para classificar outras páginas. comparamos o respectivo vetor de termos a cada um dos doze vetores tópicos. Ademais. muitas outras idéias podem ter surgido para aplicação do vetor de páginas. Uma aplicação evidente é a transferência seletiva de PageRank: comparam-se os tópicos de duas páginas. e transfere-se tanto mais PR quanto maior a semelhança de tópicos entre ambas. que eram mensais. markhorrell.htm http://www.br/sampaio/curso_de_estdados_2/ http://ead1.html http://www.cmu.com.br/~danielnm/ed/E/polE.br/cursos/C/c.eee.html http://www.edu/~guyb/realworld.shtml http://www.icmc.php?cat_id=391 http://www.com/seo/pagerank.br/euro2003/index. .rankings.europanet.br/tem_progr_hash.ulbra.html#pagerank http://www.html http://www.lcad.tche.com.br/~nonato/ED/Hashing/node33.ufpa.ig.usp.hpg.html OBS: Apostila Original criada pelo professor Élton Minetto.com.ufmg.Referências http://www.com/teste/google.br/google/ http://www-2.cs. Editada e Atualizada pelo professor José Carlos Toniazzo.infotem.globalbrasil.