PROGRAMAÇÃO II 3. FILA DINÂMICA

Tamanho: px
Começar a partir da página:

Download "PROGRAMAÇÃO II 3. FILA DINÂMICA"

Transcrição

1 3. FILA DINÂMICA PROGRAMAÇÃO II Prof. Jean Eduardo Glazar Uma fila é um tipo especial de lista na qual todas as inserções são feitas sempre depois do fim e as deleções no início. Por isso também recebe o nome de lista FIFO (First In First Out), pois o primeiro a entrar na fila é o primeiro a sair. Basta pensarmos em uma fila de banco. A idéia é a mesma. Na medida em que novas pessoas vão chegando, vão entrando após o fim da fila. Quando o caixa do banco chama, a pessoa que será atendida primeiro, e portanto, aquela que sairá da fila, será a que está no início, que foi a primeira pessoa a entrar na fila. Uma aplicação bastante utilizada de fila é a implementação de fila de impressões. Imagine uma única impressora atendendo a vários usuários em diferentes computadores em rede. Na medida em que os usuários vão mandados documentos para serem impressos, esses são enfileirados na fila, ou seja, entram após o fim da fila. A impressora sempre atende ao documento que estiver no início da fila, ou seja, que entrou primeiro. Ao imprimir o documento da frente, o mesmo é desenfileirado. Assim é feito até que não haja mais documentos na fila. A forma de implementação do TAD Fila pode utilizar alocação estática (utilizando vetores) ou alocação dinâmica. Na implementação do TAD Fila, será necessário duas informações, uma que indique o início da fila, para as remoções, e outra que indique o final da fila para as inserções. Estas indicadores serão chamados de inicio e fim, respectivamente. PRINCIPAIS FUNÇÕES CriarFila Inicia a fila vazia. FilaVazia Retorna verdadeiro se a fila estiver vazia e falso caso contrário. CriarNodoFila Aloca memória para um novo nodo e retorna o seu apontador. ObterFrente Obtém o elemento da frente da fila sem desenfileirar. Enfileirar Insere um elemento na frente da fila. Desenfileirar Obtém o elemento da frente da fila desenfileirando. Imprimir Imprime a fila. Destruir Destroi a fila, liberando a memória dos nodos. Passemos agora à implementação de fila por alocação dinâmica. Veja que as vantagens e desvantagens da implementação por vetores ou por alocação dinâmica neste caso é a mesma para os três casos: lista, pilha e fila. Por vetores, ganhamos em simplicidade, mas perdemos em espaço e por alocação dinâmica ocorre o inverso. 1

2 Abaixo, descrevemos a estrutura de dados e as funções. Perceba que a implementação de fila por alocação dinâmica é praticamente a mesma implementação de lista com cabeça e cauda, com denominações diferentes. Agora a cabeça será o início da fila e a cauda será o fim da fila. Somente poderemos inserir no final da fila (InsereFimLista) e retirar do início da fila. Fila para nós agora, será um ponteiro que sempre aponta para o nodo que se encontra no início da fila (primeiro elemento) e um ponteiro que sempre aponta para o nodo que se encontra no final da fila (último elemento). Cada nodo terá um elemento próximo que aponta para o próximo nodo da fila. A pilha vazia será representada pelo inicio e fim apontando para NULL. Ao enfileirar um novo nodo, o fim passará a apontar para este nodo e o próximo do novo nodo será NULL. Enfileirando o elemento 3: Enfileirando o elemento 5: Ao desenfileirar, o inicio passará a apontar para o próximo elemento da fila Desenfileirando: 2

3 O elemento 3 será retornado e deverá ser desalocado. Veja a mudança na estrutura de dados e nas funções abaixo. Mais uma vez estamos implementando uma fila de inteiros pela maior simplicidade, mas pode ser uma fila de qualquer tipo. Definição TYPE Informacao = RECORD { Conteudo de cada posição da fila, por exemplo: nome, cpf, telefone, etc... } TYPE Ponteiro = ^NodoFila; TYPE NodoFila = RECORD TYPE Fila = RECORD info : Informacao; prox : Ponteiro; { Próximo elemento } ant : Ponteiro; { Elemento anterior } primeiro : Ponteiro; { Primeiro da fila} ultimo : Ponteiro; { Ultimo da fila} tamanho : INTEGER; { Tamanho da Fila } ALGUMAS IMPLEMENTAÇÕES: {###### Inicializar a fila vazia ######} procedure CriarFila ( var F : Fila); begin F.primeiro := NIL; { Fila vazia. Apontador aponta para nada} F.ultimo := NIL; { Fila vazia. Apontador aponta para nada} F.tamanho := 0; end; {###### Retorna TRUE se a Fila estiver vazia ##### ####### e FALSE caso contrario ##### } FUNCTION FilaVazia ( VAR F : Fila ) : BOOLEAN; IF ( F.primeiro = NIL ) THEN FilaVazia := TRUE ELSE FilaVazia := FALSE; 3

4 {###### Aloca memória para um determinado NODO e ######} {###### retorna o apontador para este NODO. Se não for possível } {###### alocar memória, retorna NIL ######} FUNCTION CriarNodoFila ( e : informacao ) : Ponteiro; VAR aux : Ponteiro; IF MaxAvail < SIZEOF(NodoFila) { ** Testa se existe memória *} THEN WRITELN( Não existe memória suficiente ); CriarNodoFila := NIL; END ELSE NEW(aux); aux^.info := e; {** Copiar todo o registro de E para INFO} CriarNodoFila := aux; { #### Enfileira o NOVO nodo na ULTIMA posição da fila ####} { #### O NOVO nodo deve ter sido criado com a função CriarNodo ####} PROCEDURE Enfileirar (VAR F : Fila; novo : Ponteiro); IF novo = NIL THEN WRITELN('Nao existe elemento para enfileirar'); END ELSE { Inserir no FIM da Fila } novo^.prox := nil; novo^.ant := F.ultimo; IF ( F.ultimo <> nil ) THEN F.ultimo^.prox := novo ELSE F.primeiro := novo; F.ultimo := novo; F.tamanho := F.tamanho + 1; { #### Destroi a Fila liberando a memória ####} { #### Percorre a Fila desenfileirando o topo ####} PROCEDURE Destruir (VAR F : Fila); WHILE ( NOT FilaVazia(F) ) DO {*** Desenfileirar o primeiro ***} 4

5 { #### Desenfileira o elemento da PRIMEIRA posição da fila ####} { #### e libera a memória ####} PROCEDURE Desenfileirar(VAR F : Fila); VAR aux : Ponteiro; IF ( FilaVazia(F) ) THEN WRITELN('Fila Vazia') ELSE aux := F.primeiro; F.primeiro := F.primeiro^.prox; { Remover o primeiro } IF ( F.primeiro <> nil) THEN F.primeiro^.ant := nil ELSE F.ultimo := nil; F.tamanho := F.tamanho - 1; DISPOSE(aux); {*** Libera a memória ***} As demais funções ficam como exercícios. {*** Vejamos agora o programa principal utilizando esta Fila ***} {*** Declaração ***} VAR F : Fila; el : informacao; pt : Ponteiro; {*** Programa principal ***} CriarFila(F); el.nome := 'A'; el.nome := 'B'; el.nome := 'C'; el.nome := 'D'; el.nome := 'E'; el.nome := 'F'; el.nome := 'G'; Imprimir(F); {*** Imprime: A B C D E F G ***} Imprimir(F); {*** Imprime: B C D E F G ***} pt := ObterFrente(F); 5

6 IF ( pt <> nil ) THEN writeln(pt^.info.nome); {*** Imprime: B ***} Imprimir(F); {*** Imprime: C D E F G ***} Imprimir(F); {*** Imprime: D E F G ***} Imprimir(F); {*** Imprime: E F G ***} pt := ObterFrente(F); IF ( pt <> nil ) THEN writeln(pt^.info.nome); {*** Imprime: E ***} Destruir(F); {*** Não esqueça de destruir a Fila ***} readkey; END. EXERCÍCIOS: 1) Considere a implementação do TAD Fila utilizando alocação dinâmica: a) Represente a estrutura da Fila vazia e após cada inserção dos elementos 8, 4,5, 3 e 9. b) Represente a estrutura da Fila após desenfileirar um elemento. c) Represente a estrutura da Fila após desenfileirar mais um elemento. d) Represente a estrutura da Fila após inserir o elemento 2. e) Escreva uma rotina em C para imprimir a Fila. f) Escreva uma rotina em C para destruir a Fila. 2) Suponha que tenhamos um programa em C que armazene uma fila de pessoas (nomes das pessoas). Tendo em vista o ditado "Os últimos serão os primeiros", crie uma função que pegue a fila e a inverta, ou seja, quem estava no início da fila vai passar a estar no final e quem estava no final passará a estar no início. Utilize uma pilha para esta inversão. Obs: Implemente apenas a função main(), utilizando as funções da Fila e da Pilha implementadas com alocação dinâmica e não por vetores. 3) Considere que você tem à disposição duas pilhas. Mostre como elas podem ser utilizadas em conjunto para simular o funcionamento de uma fila. Crie em português estruturado a função enfileirar e a função desenfileirar utilizando estas duas pilhas. Sugestão: utilize uma pilha como espaço de armazenamento e a outra como espaço auxiliar para as operações de movimentação de dados. 6