Algoritmos e Estruturas de Dados I Prof. Daniel M. Martin (daniel.martin@ufabc.edu.br) Aula 6
Modularização Método que consiste em organizar programas grandes em pequenas partes (módulos) Cada módulo tem uma interface bem definida Em C é feita por meio de um arquivo.h Possui as estruturas (structs) utilizadas Possui cabeçalho (declaração) de funções Cada módulo tem uma implementação Em C é feita por meio de um arquivo.c
Vantagens da modularização: Módulos podem ser reusados em vários projetos Mudar a implementação de um módulo não afeta o programa principal (desde que a interface não mude) Mais rápido de recompilar o projeto quando apenas um módulo (ou apenas o programa principal) for modificado Mais fácil de debugar (você pode testar cada módulo separadamente)
Modularização em C main.c compilador executável Interface: modulo1.h Implementação: modulo1.c Interface: modulo2.h Implementação: modulo2.c
Lista Ligada Interface Deve conter as estruturas: typedef struct s_no *p_no; struct s_no { item dado; p_no prox; }; Deve conter as funções: p_no cria_no(item a); void libera(p_no x); void insere_inicio(p_no *pl, p_no y); p_no remove_inicio(p_no *pl); p_no busca(p_no L, item a);
Item Interface Deve conter a declaração de tipo: typedef int item;
Interface: item.h #ifndef ARQUIVO_ITEM_H #define ARQUIVO_ITEM_H typedef int item; #endif
Interface: lista.h #include "item.h" #ifndef ARQUIVO_LISTA_H #define ARQUIVO_LISTA_H typedef struct s_no *p_no; struct s_no { item dado; p_no prox; };
Interface: lista.h (cont.) p_no cria_no(item a); void libera(p_no x); void insere_inicio(p_no *pl, p_no y); p_no remove_inicio(p_no *pl); p_no busca(p_no L, item a); #endif
Implementação: lista.c #include <stdio.h> #include <stdlib.h> #include "item.h" #include "lista.h" void insere_inicio(p_no *pl, p_no y) { y->prox = *pl; *pl = y; } void libera(p_no x) { if (x!= NULL) free(x); }
Implementação: lista.c (cont.) p_no cria_no(item a) { p_no x = (p_no) malloc(sizeof(struct s_no)); if (x == NULL) { printf("memória insuficiente.\n"); exit(exit_failure); } x->dado = a; } return x;
Implementação: lista.c (cont.) p_no remove_inicio(p_no *pl) { p_no x = *pl; if (*pl!= NULL) *pl = (*pl)->prox; } return x;
Implementação: lista.c (cont.) p_no busca(p_no L, item a) { p_no t; for (t = L; t!= NULL; t = t->prox) if (t->dado == a) return t; } return NULL;
Implementação: main.c #include <stdio.h> #include <stdlib.h> #include "item.h" #include "lista.h" int main() { p_no t, L = NULL, x, y, z; x = cria_no(20); y = cria_no(17); z = cria_no(23);
Implementação: main.c (cont.) insere_inicio(&l, x); insere_inicio(&l, y); insere_inicio(&l, z); for (t = L; t!= NULL; t = t->prox) printf("%d ", t->dado); } printf("\n"); libera(x); libera(y); libera(z); return 0;
Compilando e excutando o código Num terminal linux faça: gcc lista.c main.c -o proglistas./proglistas Usando o Code::Blocks ou o Dev C++ faça: Adicione no projeto todos os arquivos.h Adicione no projeto todos os arquivos.c Compile e execute normalmente
Listas Ligadas Uso de Memória Chamar malloc para criar cada nó é lento Alternativa: manter uma lista ligada de nós "livres" ou disponíveis A mudança na interface lista.h é acrescentar void inicializa_lista(int n); O programa principal main.c deve chamar inicializa_lista(10); antes de chamar a função cria_no(...);
Implementação: lista.c A implementação lista.c também cresce: p_no disp; void inicializa_lista(int n) { disp = (p_no) malloc(n * sizeof(struct s_no)); if (disp == NULL) { /* testa falha */ } for (i = 0; i < n; i ++) disp[i].prox = &disp[i + 1]; } disp[n - 1].prox = NULL;
Implementação: lista.c p_no cria_no(item a) { p_no t = disp; disp = disp->prox; t->dado = a; return t; } void libera(p_no x) { x->next = disp; disp = x; }
Simulação p_no x, y, L = NULL; inicializa_lista(7); x = cria_no(20); y = cria_no(17); insere_inicio(&l, x); insere_inicio(&l, y); libera(x); libera(y);
Listas Circulares São listas ligadas onde o último elemento não aponta para NULL, mas aponta de volta para o primeiro elemento da lista. Se a lista tem um único elemento, o campo prox dele deve apontar para si mesmo.
Listas Circulares Operações primeira inserção de um nó t na lista: L = t; L->prox = L; demais inserções: t->prox = L->prox; L->prox = t; percorrer a lista: t = L; do {... t = t->prox;} while (t!= L); remover L->prox da lista: if (L!= NULL && L->prox!= L) L->prox = L->prox->prox; else L = NULL;
Listas Duplamente Ligadas São listas que possuem, além do ponteiro para o próximo nó, um ponteiro para o nó anterior Ocupam mais memória, mas dependendo da aplicação permite a utilização de algoritmos mais rápidos
Listas Duplamente Ligadas São listas que possuem, além do ponteiro para o próximo nó, um ponteiro para o nó anterior Ocupam mais memória, mas dependendo da aplicação permite a utilização de algoritmos mais rápidos NULL L NULL
Filas
Filas Seqüência dinâmica de objetos Todos os objetos são do mesmo tipo (assim como nos vetores e listas ligadas) O que caracteriza a fila é a ordem de remoção dos elementos: Se algum elemento é removido, deve ser aquele que está na fila a mais tempo
Filas Seqüência dinâmica de objetos Todos os objetos são do mesmo tipo (assim como nos vetores e listas ligadas) O que caracteriza a fila é a ordem de remoção dos elementos: Se algum elemento é removido, deve ser aquele que está na fila a mais tempo FIFO first-in first-out o primeiro elemento a entrar numa fila é também o primeiro a sair
Como implementar uma fila? Se você sabe que não mais do que n elementos serão inseridos (e removidos) da fila, você pode usar um vetor v de n elementos Dois inteiros in e fn podem ser usados para indicar o início e o final da fila in fn
Simulação (na lousa) aloca v com espaço para 10 elementos insere 23 insere 18 remove insere 13 insere 34 remove insere 55
Outra implementação de fila Se você sabe que, em qualquer instante durante a execução do programa, a fila não tem mais que n elementos (embora o número de inserções possa ser muito maior que n), então você pode usar um vetor circular v com n posições
Outra implementação de fila Se você sabe que, em qualquer instante durante a execução do programa, a fila não tem mais que n elementos (embora o número de inserções possa ser muito maior que n), então você pode usar um vetor circular v com n posições Como assim? Vetor circular?
Implementação com vetor circular Aloca um vetor v com capacidade para n + 1 elementos Usa in e fn como feito antes Trata v como um vetor circular, ou seja etc... v[n + 1] = v[0] v[n + 1] = v[1]
Implementação com vetor circular 13 14 0 12 1 in 11 10 2 3 9 4 8 7 6 5 fn
Simulação (na lousa) aloca v[10] insere 23 insere 18 remove insere 13 insere 34 remove insere 55 insere 78 insere 41 remove remove insere 16 insere 12 insere 98 insere 45 remove remove insere 5 insere 37
Interface: fila.h #include "item.h" #ifndef ARQUIVO_FILA_H #define ARQUIVO_FILA_H struct s_fila { int N; // capacidade da fila + 1 item *v; // vetor circular de itens int in, fn; }; typedef struct s_fila *p_fila;
Interface: fila.h (cont.) void inicializa_fila(p_fila F, int n); int fila_vazia(p_fila F); void enfileira(p_fila F, item a); item desenfileira(p_fila F); #endif
Implementação: fila.c #include <stdio.h> #include <stdlib.h> #include "item.h" #include "fila.h" int fila_vazia(p_fila F) { return F->in % F->N == F->fn; }
Implementação: fila.c (cont.) void inicializa_fila(p_fila F, int n) { F->v = (item *) malloc((n + 1) * sizeof(item)); if (F->v == NULL) { /* testa falha */} } F->N = n + 1; F->in = F->N; F->fn = 0; // pode ser 0 também
Implementação: fila.c (cont.) void enfileira(p_fila F, item a) { F->v[F->fn ++] = a; F->fn %= F->N; } item desenfileira(p_fila F) { F->in %= F->N; return F->v[F->in ++]; }
Outra implementação de fila Se o tamanho de uma fila pode crescer indefinidamente, você pode usar uma lista ligada para implementar uma fila Mas como?
Outra implementação de fila Se o tamanho de uma fila pode crescer indefinidamente, você pode usar uma lista ligada para implementar uma fila Mas como? Usando uma lista duplamente ligada?
Outra implementação de fila Se o tamanho de uma fila pode crescer indefinidamente, você pode usar uma lista ligada para implementar uma fila Mas como? Usando uma lista duplamente ligada? NÃO PRECISA!!!
Outra implementação de fila Matenho um ponteiro il para o primeiro nó da lista e um nó fl para o último nó da lista. No início: il = fl = NULL;
Outra implementação de fila Matenho um ponteiro il para o primeiro nó da lista e um nó fl para o último nó da lista. No início: il = fl = NULL; Para inserir item a numa fila vazia faça: il = fl = cria_no(a); Para demais inserções faça: fl->prox = cria_no(a); fl = fl->prox; Para remover um item faça: y = il; il = il->prox; // devolve y
Aplicação de Fila Calcular a distância entre pessoas no Facebook
Aplicação de Fila Calcular a distância entre pessoas no Facebook Amanda Paul