/* * Modulo: filas (ficheiro de cabecalho) * * Descricao: Implementa o conceito de fila. As operacoes permitidas com as * filas sao as associadas 'as funcoes descritas abaixo. * * Notas: * * Autores: * Manuel Menezes de Sequeira, ISCTE, 1997. */ #ifndef FILAS_H #define FILAS_H /* Inclusao do ficheiro com tipos de utilidade generica (v.g. Logico): */ #include "tipos.h" /* Definicao do tipo das variaveis que guardam manipulos de acesso 'as filas. */ typedef struct Fila *Fila; /* Definicao do tipo dos elementos que serao guardados nas filas: */ typedef int Fdados; #include <limits.h> #define FerroDados INT_MIN /* Cria uma nova fila, vazia, devolvendo um manipulo (um endereco) para a mesma. Podem ser criadas quantas filas se desejar, desde que para isso haja memoria. */ Fila Fcria(void); /* Destroi a fila associada ao manipulo f passado como argumento. Toda a memoria associada 'a fila e' libertada. O manipulo (endereco) da fila torna-se invalido depois de passado a esta funcao. */ void Fdestroi(Fila f); /* Insere os dados d no fim da fila cujo manipulo e' f. Se a insercao tiver sucesso, devolve Verdadeiro, no caso contrario devolve Falso. */ Logico Finsere(Fila f, Fdados d); /* Remove o elemento do inicio da fila cujo manipulo e' f. Se a fila estiver vazia, devolve Falso, caso contrario devolve Verdadeiro. */ Logico Fremove(Fila f); /* Devolve os dados do elemento no inicio da fila cujo manipulo e' f. O resultado e' indefinido se a fila estiver vazia. */ Fdados Ffrente(Fila f); /* Devolve o comprimento (numero de elementos) da fila cujo manipulo e' f: */ size_t Fcomprimento(Fila f); #endif /* FILAS_H */
/*
* Modulo: filas.c
*
* Descricao: Implementa o conceito de fila. As operacoes permitidas com as
* filas sao as associadas 'as funcoes descritas abaixo.
*
* Notas:
*
* Autores:
* Manuel Menezes de Sequeira, ISCTE, 1997.
*/
#include <stdlib.h>
#include "filas.h"
struct Fila
{
size_t i; /* indice do inicio da fila. */
size_t f; /* indice do fim da fila. */
size_t n; /* numero de elementos na fila
(comprimento.) */
size_t t; /* tamanho corrente da matriz. */
Fdados *m; /* matriz de elementos. */
};
#define INCR 4U
#if INCR == 0U
#error Valor do incremento invalido.
#endif
/* Cria uma nova fila, vazia, devolvendo um manipulo (um endereco) para a
mesma. Podem ser criadas quantas filas se desejar, desde que para isso
haja memoria. */
Fila Fcria(void)
{
Fila f;
if((f = malloc(sizeof *f)) == NULL)
return NULL;
f->t = INCR;
if((f->m = calloc(f->t, sizeof *f->m)) == NULL)
{
free(f);
return NULL;
}
f->i = f->f = f->n = 0U;
return f;
}
/* Destroi a fila associada ao manipulo f passado como argumento. Toda a
memoria associada 'a fila e' libertada. O manipulo (endereco) da fila
torna-se invalido depois de passado a esta funcao. */
void Fdestroi(Fila f)
{
if(f != NULL)
{
free(f->m);
free(f);
}
}
/* Calculo do mdc pelo metodo de Euclides: */
static size_t mdc(size_t m, size_t n)
{
size_t r;
while((r = m % n) != 0)
{
m = n;
n = r;
}
return n;
}
/*
* Reorganiza a fila. Este e' um problema interessante. E' necessario
* colocar o primeiro da fila na posicao 0 da matriz. Isso significa
* deslocar todos os elementos de f->i para a esquerda. Nao esquecer que a
* matriz esta' cheia nesta fase! Como fazer os deslocamentos? A solucao
* mais evidente e' colocar numa matriz auxiliar os f->i primeiros elementos
* da matriz, deslocar os outros, e copiar da matriz auxiliar para o final
* da matriz. Mas ha' uma solucao que so' precisa duma posicao de memoria
* extra (alem do espaco usado pelas variaveis de indice). T.P.C.: perceber
* os ciclos abaixo (experimente com t->n = 12 e t->i = 1,...,11).
*
* (Nota: quando esta funcao e' chamada temos f->n = f->t e f->i = f->f.)
*/
static void reorganiza(Fila f)
{
size_t n; /* tamanho da matriz. */
size_t d; /* deslocamento. */
size_t c; /* numero de ciclos de deslocamento. */
size_t i; /* inicio dos ciclos. */
size_t j, k; /* para o ciclo de transferencias. */
/* Verificar casos em que os deslocamentos a realizar nao tem qualquer
efeito: */
if(f->n == 1U || f->i == 0U)
return;
/* Guardar tamanho da matriz e deslocamento a realizar em n e d: */
n = f->n;
d = f->i;
/* Calcular o numero de ciclos de transferencia a realizar: */
c = mdc(n, d);
/* Realizar o c ciclos de tranferencia: */
for(i = 0U; i < c; i++)
{
/* Realizar um ciclo de transferencias: */
int aux = f->m[i];
for(j = i, k = (i + d) % n; k != i; j = k, k = (k + d) % n)
f->m[j] = f->m[k];
f->m[j] = aux;
}
/* Agora o inicio e o fim (ou melhor, o proximo final) estao na origem,
como se desejava: */
f->i = f->f = 0U;
}
/* Redimensiona a fila (reorganizando-a primeiro): */
static Logico redimensiona(Fila f)
{
Fdados *m;
size_t t;
/* Antes de reservar memoria reorganizamos a matriz de modo a que o
primeiro elemento da fila esteja na posicao 0: */
reorganiza(f);
/* Agora ja' podemos redimensionar a matriz: */
t = f->t + INCR;
if((m = realloc(f->m, t * sizeof(Fdados))) == NULL)
return Insucesso;
f->m = m; /* nova matriz redimensionada. */
f->t = t; /* novo tamanho. */
f->f = f->n; /* novo final. */
return Sucesso;
}
/* Insere os dados d no fim da fila cujo manipulo e' f. Se a insercao tiver
sucesso, devolve Verdadeiro, no caso contrario devolve Falso. */
Logico Finsere(Fila f, Fdados d)
{
if(f == NULL)
return Insucesso;
/* Se nao houver espaco redimensionar: */
if(f->n == f->t && !redimensiona(f))
return Insucesso;
/* Agora ha' espaco: */
f->m[f->f] = d;
if(++f->f == f->t) /* deu a volta? */
f->f = 0U;
f->n++;
return Sucesso;
}
/* Remove o elemento do inicio da fila cujo manipulo e' f. Se a fila estiver
vazia, devolve Falso, caso contrario devolve Verdadeiro. */
Logico Fremove(Fila f)
{
if(f == NULL || f->n == 0U)
return Insucesso;
if(++f->i == f->t) /* deu a volta? */
f->i = 0U;
f->n--;
return Sucesso;
}
/* Devolve os dados do elemento no inicio da fila cujo manipulo e' f. O
resultado e' indefinido se a fila estiver vazia. */
Fdados Ffrente(Fila f)
{
if(f == NULL || f->n == 0U)
return FerroDados;
return f->m[f->i];
}
/* Devolve o comprimento (numero de elementos) da fila cujo manipulo e' f: */
size_t Fcomprimento(Fila f)
{
if(f == NULL)
return 0U;
return f->n;
}
#include <stdio.h>
#include <stdlib.h>
#include "filas.h"
#include "menu.h"
#include "teclado.h"
int main(void)
{
Fila f;
int opcao;
int valor;
f = Fcria();
do
{
switch(opcao = MNpedeOpcao("I - Insere.\n"
"R - Remove.\n"
"P - Primeiro.\n"
"S - Sair.\n", '\n'))
{
case 'I':
scanf("%d", &valor); getchar();
if(!Finsere(f, valor))
printf("Erro inserindo.\n");
break;
case 'R':
if(!Fremove(f))
printf("Erro removendo (fila vazia?).\n");
break;
case 'P':
if((valor = Ffrente(f)) == FerroDados)
printf("Erro obtendo primeiro (fila vazia?).\n");
else
printf("Frente: %d.\n", valor);
break;
}
}
while(opcao != 'S' && opcao != EOF);
Fdestroi(f);
return EXIT_SUCCESS;
}
| Página
concebida e mantida por Eng. Manuel Menezes de Sequeira (última actualização 2006/07/07) Copyright © 1996-2001 ISCTE |
||||