Curso : Tecnologia em Desenvolvimento de Sistemas - AEMS Série : 3 º Período - 1 º Semestre de 2011 Professora : Elzi Ap. Gil 3. LISTAS LINEARES PARTE - III Disciplina - Estrutura de Dados Segundo Pereira(2002), uma das formas mais comunente usadas para se manter dados agrupados é a lista. No dia-a-dia das pessoas as listas têm sem mostrado um recuros bastante útil e eficiente, em computação, a lista é uma das estruturas de dados mais empregados no desenvolvimento de programas. 3.1. Fundamentos Uma lista linear é uma coleção L: [a 1, a 2, a 3,...a n ], N >= 0, cuja propriedade estrutural baseia-se apenas na posição relativa dos elementos, que são dispostos linearmente. Se n = 0, dizemos que a lista L é vazia; caso contrário, são válidas as seguintes propriedade: a 1 é o primeiro elemento de L; a n é o último elemento de L; a k, 1<k<n, é precedido pelo elemento a k-1 e seguido por a k+1. Entre as divesas operações que podemos realizar sobre listas, tem-se: acessar um elemento qualquer da lista; inserir um elemento nume posição específica da lista; remover um elemento nume posição específica da lista; combinar duas listas em uma única; particionar um a lista em duas; obter cópia de uma lista; determinar o total de elementos na lista; ordenar os elementos da lista; procurar um determinado elemento na lista; apagar uma lista; outras... Considerando-se somente as operações de acesso, inserção e remoção, restritas aos extremos da lista, temos casos especiais que aparecem muito freqüentemente na modelagem de problemas a serem resolvidos por computador, conforme especificado a seguir: Pilha : lista linear onde todas as inserções, remoções e acessos são realizados em um único extremo. Também denomidadas listas LIFO (Last-In/First-Out último que entra / primeiro que sai). Fila : lista linear onde todas as inserções são feitas num certo extremo e todas as remoções e acessos são realizados no outro. Também denominadas listas FIFO (First-In/ First-Out primeiro que entra/primeiro que sai). 1
Fila Dupla : lista linear onde as inserções, remoções ou acessos são realizados em qualquer extremo. Filas duplas são também deniminadas DEQUE (Double-Ended QUEue fila de extremidade dupla). Uma Fila Dupla pode ainda gerar dois casos especiais: Fila Dupla de Entrada Restria e Fila Dupla de Saída Restrita. 3.2. Considerações sobre implementação Ao codificar um programa que utiliza listas para armazenar dados, dificilmente iremos usar todas as operações que podem ser feitas com listas lineares. Por exemplo, uma implementação que facilite o acesso a qualquer elemento no meio da lista, ceramente dificultara a inserção e a remoção de elementos no meio da mesma, como veremos futuramente. A seguir estaremos apresentado algumas alternativas de com implementar listas lineares na memória do computador. Assim, dependendo das operações realizadas com maior freqüencia, pode-se fazer escolhas que tornem a nossa aplicação a mais eficiente possível. 4. PILHAS Implementação Seqüencial A Pilha é uma das estruturas mais úteis em computação. Uma infinidade de problemas da área pedem ser resolvidos com o uso delas. 4.1. Fundamentos A Pilha é um tipo especial de lista linear em que todas as operações de inserção e remoção são realizadas numa mesma extremidade, denominada topo. Cada vez que um elemento deve ser inserido na pilha, ele é colocado no seu topo; e em qualquer momento, apenas aquele posicionado no topo da pilha pode ser removido. Está lista, por definição, é uma estrutura dinâmica, ou seja, é uma coleção que pode ser aumentar e diminirdurante a sua existência. O exemplo mais comum do quotidiano é uma pilha de pratos, onde o último prato colocado é o primeiro a ser usado (removido). Uma pilha suporta três operações básicas, tradicionalmente denominadas como: Top : acessa o elemento posicionado no topo da pilha; Push (empurre para baixo): insere um novo elemento no topo da pilha; Pop (saltar para cima) : remove um elemento do topo da pilha. Sendo P uma pilha e x um elemento qualquer, a operação Push(P,x) aumenta o tamanho da pilha P, acrescentando o elemento x no seu topo. A operação Pop(P) faz com que a pilha diminua, removendo e retornando o elemento existente no topo. Das três operações básicas, a única que não altera o estado da pilha é Top(P); ela simplesmente retorna uma cópia do elemento existente no topo da pilha, sem removê-lo. A seguir temos uma tabela com estas operações intereagem para alterar o estado de uma pilha P. e pode-se observar com estas operações 2
Operação Estado da Pilha Resultado ----------------------- P : [ ] ------------------ Push ( P, a ) P : [ a ] ------------------ Push ( P, b ) P : [ b, a ] ------------------ Push ( P, c ) P : [ c, b, a ] ------------------ Pop ( P ) P : [ b, a ] c Pop ( P ) P : [ a ] b Push ( P, d ) P : [ d, a ] ------------------ Push ( P, e ) P : [ e, d, a ] ------------------ top ( P ) P : [ e, d, a ] e Pop ( P ) P : [ d, a ] e Pop ( p ) P : [ a ] d Para visualizar melhor, a seguir vamos representar a pilha na forma de um gráfico, crescendo na vertical, de baixo para cima, conforme a seguir: P : [ a n, a n-1,..., a 2, a 1 ] a n a n-1... a 2 a 1 topo base 4.2. Introdução ao uso de pilhas Além das operações para inserir (Push), remover (Pop) e verificar o elemento do topo (Top), será necessário mais três operações essenciais para manipular pilhas: Init : inicializa a pilha no estado vazia ; IsEmpty : verifica se a pilha está vazia; IsFull : verifica se a pilha está cheia. Sempre que uma variável é criada, ela permanece com conteúdo indefinido, até que um determinado valor seja a ela atribuido. Geralmente, a criação de uma variável se restringe apenas à alocação da área de memória necessária para representa-la; nenhum valor é armazenado nesta área, até que uma instrução específica para esta finalidade seja executada. A operação Init ( P ) tem como objetivo definir um estado inicial para a pilha P. A pilha é iniciadao no estado vazia. Para verificar se uma pilha P está vazia, podemos usar a função lógica IsEmpty ( P ), que toma como argumento a pulha em que estamos interessados e retorna verdadeiro somente se ela estiver vazia, sem nenhum elemento armazenado. A funçao IsFull ( P ) é usada para verificar se uma pilha 3
está cheia, isto é, ela retorna verdadeiro somente quando não há mais espaço para armazenar nenhum elemento na pilha. Exemplo 1 - O programa deverá ser informado um valor decimal inteiro positivo e, em seguida, calcular e mostrar o número no sistema binário. Nota: para transforma um número decimal em binário, devemos dividi-lo sucessivamente por 2, até obtermos um quociente igual a 0. Neste momento, os restos obtidos das divisões devem ser tomados em ordem inversa, conforme a seguir: 13 / 2 = 6 resto 1 6 / 2 = 3 resto 0 3 / 2 = 1 resto 1 1 / 2 = 0 resto 1 Número decima 13, com número binário 1101. Programa Pascal; program Dec_Bin; uses Pilhas; var P : Pilha; x,n : integer; begin writeln ( Digite um inteiro decimal positivo : ); readln(n); Init(P); {torba a pilha vazia} repeat end. x := n mod 2; {calcula o resto da divisão} Push (P,x); {empilha o resto} n := n div 2; { calcula quociente} until n=0; write ( Correspondente binário: ); while not IsEmpty(P) do {enquanto a pilha não estiver vazia faça} begin x := Pop(P); {desempilha o resto} write ( x ); {imprime o resto} end; Depois de ler o valor de n a ser convertido e inicializar a pilha, o programa inicia um laço que se repete até que seja obtido um quociente nulo. Este laço (repeat) executa dois comandos: o primeiro deles calcula o resto da divisão inteira (mod) de n por 2, este resto é passado à rotina Push pra ser armazenado na pilha P; o segundo comando altera a variável n, de modo que ela passe a armazenar o quociente da divisão inteira (div) do valor n por 2. E algum momento o quociente será zero e a repetição terminará. 4
Após a impressão da frase Correspondente binário:, o segundo laço (while) entra em execução, finalizando somente quando a pilha estiver vazia. Enquanto a pilha não esvaziar, a função (Pop) retira um valor do topo da pilha que é então impresso. Quando todos os restos armazenados na pilha já tiverem sido impressos, a pilha ficará vazia e a repetição terminará. A instrução uses, no início do programa, server para indicar que o programa precisará utilizar o tipo de dados pilha, e será discutida mais adiante. Exercício de fixação: 1 - Mostre a situação da pilha P, inicialmente vazia, após a execução de cada uma das operações a seguir: Push ( P, a); Push ( P, b); Push ( P, c); Push(P, Top(P)); Push ( P, Pop(P)); Pop( P ); Push ( P, e); Pop ( P ); 2 Escreva um programa para ler uma frase e imprimila com as palavras invertidas. Exemplo : a frase A pilha do gato deve sair A ahlip od otag. dicas : A função length(variável), retorna o tamanho da variável (número de caracteres) Para a variável Nome do tipo string, quando Nome = Pedro : length(nome) = 5 Nome[1] = P, Nome[2]= e, Nome[3]= d, Nome[4]= r, Nome[5]= o. Bibliografia: PEREIRA, Silvio do Lago. Estrututras de Dados Fundamentais Conceitos e Aplicações. 6 ed.. São Paulo: Érica, 2002. 5