• Nenhum resultado encontrado

O Programa 1.8 copia o conteúdo arquivo Velho no arquivo Novo. Ob- serve que os nomes dos arquivos aparecem como parâmetros do programa. E importante observar que a atribuição de nomes de arquivos externos, ao programa varia de compilador para compilador. Por exempla, no caso do Turbo Pascal3 a atribuição do nome externo de um arquivo a uma variável

interna ao programa é realizada através do comando assign e não como parâmetros do programa.

Os tipos apontadores são úteis para criar estruturas de dados encadea-

das, do tipo listas, árvores, e grafos. Um apontador é uma variável que re-

ferencia uma outra variável alocada dinamicamente. Em geral a variável referenciada é definida como um registro que inclui também um apontador para outro elemento do mesmo tipo.

Exemplo:

type Apontador = ^Nodo; type Nodo = record

Chave : integer Apont : Apontador;

end;

Dada uma variável

30 CAPíTULO 1. INTRODUÇÃO

var Lista: Apontador;

é possível criar uma lista como ilustrada na Figura 1.7.

Figura 1.7: Lista encadeada

Notas Bibliográficas

Estudos básicos sobre os conceitos de algoritmos, estruturas de dados e pro- gramas podem ser encontrados em Dahl, Dijkstra e Hoare (1972), Dijkstra ( 1971), Dijkstra (1976), Hoare (1969), Wirth (1971), Wirth (1974), Wirth ( 1976). Mais recentemente Manber (1988) e Manber (1989) tratam da utilização de indução matemática para o projeto de algoritmos.

A análise assintótica de algoritmos é hoje a principal medida de eficiência para algoritmos. Existem muitos livros que apresentam técnicas para analisar algoritmos, tais como somatórios, equações de recorrência, árvores de decisão, oráculos, dentre outras. Knuth (1968), Knuth (1973), Knuth (1981), Graham, Knuth e Patashnik (1989), Aho, Hoperoft e Ullman (1974), Stanat e McAllister (1977), Cormem, Leiserson e Rivest (1990), Manber (1989), Ho- rowitz e Sahni (1978), Greene e Knuth (1982), são alguns exemplos. Artigos gerais sobre o tópico incluem Knuth (1971), Knuth (1976), Weide (1977), Lueker (1980), Flajolet e Vitter (1987). Tarjan (1985) apresenta custo

amortizado: se certa parte de um algoritmo é executada muitas vezes, cada

vez com um tempo de execução diferente, ao invés de considerar o pior caso em cada execução, os diferentes custos são amortizados.

Existe uma enorme quantidade de livros sobre a linguagem Pascal. O Pascal padrão foi definido originalmente em Jensen e Wirth (1974). O livro de Cooper (1983) apresenta uma descrição precisa e ao mesmo tempo didática do Pascal padrão.

Exercícios

1) Dê o conceito de • algoritmo

34 CAPITULO 1.

INTRODUÇÃO

12) Apresente um algoritmo para obter o maior e o segundo maior elemento de um conjunto. Apresente também uma análise do algoritmo. Você acha o seu algoritmo eficiente? Por quê? Procure comprovar suas respostas.

13) São dados 2n números distintos distribuidos em dois arranjos com n elementos A e B ordenados de maneira tal que (Carvalho, 1992):

A[1] > A[2] > A[3] > • • • > A[n] e B[1] > B[2] > B[3] > • • • > B[n].

O problema é achar o n-ésimo maior número dentre estes 2n elementos. a) Obtenha um limite inferior para o número de comparações ne-

cessárias para resolver este problema.

b) Apresente um algoritmo cuja complexidade no pior caso seja iqual ao valor obtido na letra a), ou seja, um algoritmo ótimo.

Capítulo 2

Estruturas de Dados Básicas

2.1 Listas Lineares

Uma das formas mais simples de interligar os elementos de um conjunto é através de uma lista. Lista é uma estrutura onde as operações inserir, retirar e localizar são definidas. Listas são estruturas muito flexíveis porque podem crescer ou diminuir de tamanho durante a execução de um programa, de acordo com a demanda. Itens podem ser acessados, inseridos ou retirados de uma lista. Duas listas podem ser concatenadas para formar uma lista única, assim como uma lista pode ser partida em duas ou mais listas.

Listas são adequadas para aplicações onde não é possível prever a de- manda por memória, permitindo a manipulação de quantidades imprevisíveis de dados, de formato também imprevisível. Listas são úteis em aplicações tais como manipulação simbólica, gerência de memória, simulação e compi- ladores. Na manipulação simbólica os termos de uma fórmula podem crescer sem limites. Em simulação dirigida por relógio pode ser criado um número imprevisível de processos, os quais têm que ser escalonados para execução de acordo com alguma ordem predefinida.

Uma lista linear é uma seqüência de zero ou mais itens x1, x2,•••,xn, onde xi é de um determinado tipo e n representa o tamanho da lista linear. Sua

principal propriedade estrutural envolve as posições relativas dos itens em uma dimensão. Assumindo n ≥ 1, xy1 é o primeiro item da lista e xn é o

último item da lista. Em geral xi precede xi+1 para i = 1, 2, ••• ,n — 1, e xi sucede xa_1 para i = 2, 3, ••• , n. Em outras palavras, o elemento xi é dito

estar na i-ésima posição da lista.

Para criar um tipo abstrato de dados Lista, é necessário definir um conjunto de operações sobre os objetos do tipo Lista. 0 conjunto de operações a ser definido depende de cada aplicação, não existindo um con- junto de operações que seja adequado a todas as aplicações. Um conjunto

36 CAPíTULO 36. ESTRUTURAS DE DADOS

BÁSICAS

de operações necessário a uma maioria de aplicações é apresentado a seguir. Outras sugestões para o conjunto de operações podem ser encontradas em Knuth (1968, p.235) e Aho, Hoperoft e Ullman (1983, pp.38-39).

1. Criar uma lista linear vazia.

2. Inserir um novo item imediatamente após o i-ésimo item. 3. Retirar o i-ésimo item.

4. Localizar o i-ésimo item para examinar e/ou alterar o conteúdo de seus componentes.

5. Combinar duas ou mais listas lineares em uma lista única. 6. Partir uma lista linear em duas ou mais listas.

7. Fazer uma cópia da lista linear.

8. Ordenar os itens da lista em ordem ascendente ou descendente, de acordo com alguns de seus componentes.

9. Pesquisar a ocorrência de um item com um valor particular em algum componente.

0 item 8 acima é objeto de um estudo cuidadoso no Capítulo 3, e o item 9 será tratado nos Capítulos 4 e 5.

Um conjunto de operações necessário para uma aplicação exemplo a ser apresentada mais adiante é apresentado a seguir.

1. FLVazia(Lista). Faz a lista ficar vazia.

2. Insere(x, Lista). Insere x após o último item da lista.

3. Retira(p, Lista, x). Retorna o item x que está na posição p da lista, retirando-o da lista e deslocando os itens a partir da posição p+l para as posições anteriores.

4. Vazia(Lista). Esta função retorna true se a lista está vazia; senão retorna false.

5. Imprime(Lista). Imprime os itens da lista na ordem de ocorrência. Existem várias estruturas de dados que podem ser usadas para representar listas lineares, cada uma com vantagens e desvantagens particulares. As duas representações mais utilizadas são as implementações através de arran- jos e de apontadores. A implementação através de cursores (Aho, Hoperoft e Ullman, 1983, pp. 48) pode ser útil em algumas aplicações.

2.37. LISTAS LINEARES 37

2.1.1 Implementação de Listas A t r a v é s de Arranjo

s

Em um tipo estruturado arranjo, os itens da lista são armazenados em posições contíguas de memória, conforme ilustra a Figura 2.1. Neste caso a lista pode ser percorrida em qualquer direção. A inserção de um novo item pode ser realizada após o último item com custo constante. A inserção de um novo item no meio da lista requer um deslocamento de todos os itens localizados após o ponto de inserção. Da mesma forma, retirar um item do início da lista requer um deslocamento de itens para preencher o espaço deixado vazio.

Figura 2.1: Implementação de uma lista através de arranjo

O campo Item é o principal componente do registro TipoLista mostrado no Programa 2.1. Os itens são armazenados em um array de tamanho suficiente para armazenar a lista. 0 campo Ultimo do registro TipoLista contém um apontador para a posição seguinte a do último elemento da lista. 0 i-ésimo item da lista está armazenado na i-ésima posição do array, 1 < i <Ultimo. A constante MaxTam define o tamanho máximo permitido para a lista.

Uma possível implementação para as cinco operações definidas anterior- mente é mostrada no Programa 2.2. Observe que Lista é passada como var ( por referência), mesmo nos procedimentos em que Lista não é modificada ( como, por exemplo, a função Vazia) por razões de eficiência, porque desta forma a estrutura Lista não é copiada a cada chamada do procedimento.

A implementação de listas através de arranjos tem como vantagem a economia de memória, pois os apontadores são implícitos nesta estrutura. Como desvantagens citamos: (i) o custo para inserir ou retirar itens da lista, que pode causar um deslocamento de todos os itens, no pior caso; (ii) em aplicações em que não existe previsão sobre o crescimento da lista, a utilização de arranjos em linguagens como o Pascal pode ser problemática porque neste caso o tamanho máximo da lista tem que ser definido em tempo de compilação.

CAPíTULO 2. ESTRUTURAS DE DADOS BÁSICAS

Documentos relacionados