Fila dinâmica
Definição da fila dinâmica
A definição de uma fila dinâmica é bastante similar à definição de uma pilha dinâmica. A diferença é que, agora, temos dois ponteiros em FILA, um para o inicio e outro para o fim da fila. Você verá que todo o processo acaba sendo mais simples do que fila estática.
typedef struct{
int chave;
} REGISTRO;
typedef struct item{
REGISTRO r;
struct item* prox;
} ITEM;
typedef struct{
ITEM *inicio;
ITEM *fim;
} FILA;
Inicializando
A inicialização da FILA envolve basicamente definir os valores dos ponteiros de inicio e fim como NULL:
void inicializar(FILA *f){
f->inicio = NULL;
f->fim = NULL;
}
Inserindo elementos
A inserção de elementos também depende da função criarItem. Ela, no entanto, é idêntica à usada para a criação de itens da pilha.
ITEM* criarItem(REGISTRO r){
ITEM* novo = (ITEM*) calloc(1,sizeof(ITEM));
if(novo){
novo->r = r;
novo->prox = NULL;
}
return novo;
}
A diferença está na lógica da função inserir. Vejamos:
void inserir(FILA *f, REGISTRO r){
ITEM *novo = criarItem(r);
if(!novo) return;
if(!f->fim){
f->inicio = novo;
f->fim = novo;
}
else{
f->fim->prox = novo;
f->fim = novo;
}
}
Como numa fila a inserção acontece sempre no fim, primeiro verificamos se a fila possui um fim atualmente. São duas possibilidades:
- Se
f->fim == NULL(não tem fim), o item a ser inserido será o primeiro. Logo, ele é tanto o início quanto o fim da fila; - Se a fila já tem fim, precisamos informar ao antigo último item que agora tem mais alguém na fila. Depois, apontamos o fim da fila para o novo elemento.
Simples, não?
Remoção do elemento
Ao removermos um elemento, não apenas o excluímos da fila, mas o retornamos - para que ele possa ser utilizado por alguma outra função. Pelo menos essa é o entendimento que estamos usando nesta implementação.
Por isso, neste caso, a função remover retorna um ITEM*. A lógica dela é: se a fila tiver início, ou seja, não está vazia, faça o seguinte:
- Crie um ponteiro auxiliar que guarde o atual início da fila;
- Faça o início da fila apontar para o próximo item;
- Se a fila passar a não ter mais início, ela também não tem mais fim;
- Retorne o elemento que era o início da fila;
ITEM* remover(FILA *f){
if(f->inicio){
ITEM *aux = f->inicio;
f->inicio = f->inicio->prox;
if(!f->inicio) f->fim = NULL;
return aux;
}
else return NULL;
}
Imprimindo a fila
O processo de imprimir talvez seja o mais simples. Começamos pelo início da fila. Se ele não for nulo, imprimimos o seu valor e, depois, seguimos para o próximo elemento.
void imprimir(FILA *f){
ITEM *aux = f->inicio;
while(aux){
printf("%d\n", aux->r.chave);
aux = aux->prox;
}
}
Limpando a fila
Ao terminarmos de usar uma fila dinâmica, precisamos fazer a liberação do espaço ocupado por ela. No nosso caso, a necessidade envolvem o espaço ocupado pelos itens, que foram criados dinamicamente pela função criarItem. A função de liberar memória é basicamente uma adaptação da impressão:
void liberar(FILA *f){
ITEM *aux = f->inicio;
while(aux){
ITEM *exc = aux;
aux = aux->prox;
free(exc);
}
inicializar(f);
}
Exemplo completo
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct{
int chave;
} REGISTRO;
typedef struct item{
REGISTRO r;
struct item* prox;
} ITEM;
typedef struct{
ITEM *inicio;
ITEM *fim;
} FILA;
void inicializar(FILA *f){
f->inicio = NULL;
f->fim = NULL;
}
ITEM* criarItem(REGISTRO r){
ITEM* novo = (ITEM*) calloc(1,sizeof(ITEM));
if(novo){
novo->r = r;
novo->prox = NULL;
}
return novo;
}
void inserir(FILA *f, REGISTRO r){
ITEM *novo = criarItem(r);
if(!novo) return;
if(!f->fim){
f->inicio = novo;
f->fim = novo;
}
else{
f->fim->prox = novo;
f->fim = novo;
}
}
ITEM* remover(FILA *f){
if(f->inicio){
ITEM *aux = f->inicio;
f->inicio = f->inicio->prox;
if(!f->inicio) f->fim = NULL;
return aux;
}
else return NULL;
}
void imprimir(FILA *f){
ITEM *aux = f->inicio;
while(aux){
printf("%d\n", aux->r.chave);
aux = aux->prox;
}
}
void liberar(FILA *f){
ITEM *aux = f->inicio;
while(aux){
ITEM *exc = aux;
aux = aux->prox;
free(exc);
}
inicializar(f);
}
int main(void){
FILA f;
inicializar(&f);
inserir(&f, (REGISTRO){10});
inserir(&f, (REGISTRO){20});
inserir(&f, (REGISTRO){30});
inserir(&f, (REGISTRO){40});
/* Checar a remoção */
ITEM *rem = remover(&f);
if(rem){
printf("Removido: %d\n", rem->r.chave);
free(rem);
}
imprimir(&f);
liberar(&f);
return 0;
}