From: Alexandre P Francisco Date: Tue, 16 Feb 2016 18:50:13 +0000 (+0000) Subject: Add projects for 2013/14 s1. X-Git-Url: http://web.ist.utl.pt/aplf/git/?a=commitdiff_plain;h=bfad9ba7996e8020a9aa2f467cd63fec7411df9f;p=iaed.git Add projects for 2013/14 s1. --- diff --git a/1314s1p1.c b/1314s1p1.c new file mode 100644 index 0000000..9ccebc8 --- /dev/null +++ b/1314s1p1.c @@ -0,0 +1,647 @@ +/** + * @file proj1.c + * @brief Implementacao do primeiro projecto de IAED. + */ +#include +#include +#include + +#define P 5 +#define M 3 +#define O 5 +#define LEN 10 + +/** + * @brief Estrutura que representa um produto. + */ +typedef struct { + char nome[LEN + 1]; + double m[M], perdas, k_mo, k_en, k_eq, vendas, pvenda; +} produto_t; + +/** + * @brief Estrutura que representa uma materia. + */ +typedef struct { + char nome[LEN + 1]; + double custo; +} materia_t; + +/** + * Variaveis locais ao programa. + */ +static produto_t produto[P]; +static materia_t materia[M]; +static double orcamento[O]; + +/** + * Declaracao das funcaoes utilizadas neste programa. + */ +void go_d(); +void go_d_i(); +void go_d_j(); +void go_d_y(); +void go_d_v(); +void go_d_z(); +void go_d_p(); +void go_d_m(); +void go_d_n(); +void go_d_q(); +void go_d_o(); +void go_d_c(); + +void go_c(); +void go_w(); +void go_t(); +void go_v(); +void go_x(); + +double custo_a(); +double custo_b(int p); +double custo_c(int p); +double custo_d(int p); +double custo_e(); +double custo_f(int p); + +double custo_tot(int p); +double custo_ind(int p); +double custo_mpee(int p); +double margem(int p, double d); + +/** + * @brief Funcao main. + * + * @return Codigo de estado de saida do programa. + */ +int +main() +{ + char comando; + + while (1) { + /* Comandos: d(3, 5 15) c(0) w(1) t(0) v(2) x(1) */ + comando = getchar(); + + /* Processa o comando. */ + switch (comando) { + case 'd': + go_d(); + break; + case 'c': + go_c(); + break; + case 'w': + go_w(); + break; + case 't': + go_t(); + break; + case 'v': + go_v(); + break; + case 'x': + go_x(); + /* Este comando termina o programa. */ + return EXIT_SUCCESS; + default: + /* Nao devemos chegar aqui. */ + assert(0); + } + } + + /* Nao devemos chegar aqui em situacoes normais. */ + return EXIT_FAILURE; +} + +/** + * @brief Funcao para processar o comando 'd'. + */ +void +go_d() +{ + char subcomando; + + getchar(); /* Apanha o espaco. */ + subcomando = getchar(); + + /* Processa o subcomando. */ + switch (subcomando) { + case 'i': + go_d_i(); + break; + case 'j': + go_d_j(); + break; + case 'y': + go_d_y(); + break; + case 'v': + go_d_v(); + break; + case 'z': + go_d_z(); + break; + case 'p': + go_d_p(); + break; + case 'm': + go_d_m(); + break; + case 'n': + go_d_n(); + break; + case 'q': + go_d_q(); + break; + case 'o': + go_d_o(); + break; + case 'c': + go_d_c(); + break; + default: + /* Nao devemos chegar aqui. */ + assert(0); + } +} + +/** + * @brief Funcao para processar o comando 'd i'. + */ +void +go_d_i() +{ + int i = 0; + + for (i = 0; i < P; i++) { + /* Ler, e escrever como solicitado. */ + scanf("%s", produto[i].nome); + printf ("%s", produto[i].nome); + if (i < P -1) + printf(" "); + } + putchar(getchar()); /* Apanha e escreve fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd j'. + */ +void +go_d_j() +{ + int i = 0; + + for (i = 0; i < M; i++) { + /* Ler, e escrever como solicitado. */ + scanf("%s", materia[i].nome); + printf ("%s", materia[i].nome); + if (i < M -1) + printf(" "); + } + putchar(getchar()); /* Apanha e escreve fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd y'. + */ +void +go_d_y() +{ + int i = 0; + + for (i = 0; i < M; i++) + scanf("%lf", &materia[i].custo); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd v'. + */ +void +go_d_v() +{ + int i = 0; + + for (i = 0; i < P; i++) + scanf("%lf", &produto[i].vendas); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd z'. + */ +void +go_d_z() +{ + int i = 0; + + for (i = 0; i < P; i++) + scanf("%lf", &produto[i].pvenda); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd p'. + */ +void +go_d_p() +{ + int i = 0; + + for (i = 0; i < P; i++) + scanf("%lf", &produto[i].perdas); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd m'. + */ +void +go_d_m() +{ + int i = 0; + + for (i = 0; i < P; i++) + scanf("%lf", &produto[i].k_mo); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd n'. + */ +void +go_d_n() +{ + int i = 0; + + for (i = 0; i < P; i++) + scanf("%lf", &produto[i].k_en); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd q'. + */ +void +go_d_q() +{ + int i = 0; + + for (i = 0; i < P; i++) + scanf("%lf", &produto[i].k_eq); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd o'. + */ +void +go_d_o() +{ + int i = 0; + + for (i = 0; i < O; i++) + scanf("%lf", &orcamento[i]); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'd c'. + */ +void +go_d_c() +{ + int i = 0, j = 0; + + /* Constituicao dos produtos. */ + for (i = 0; i < P; i++) + for (j = 0; j < M; j++) + scanf("%lf", &produto[i].m[j]); + getchar(); /* Apanha fim de linha. */ +} + +/** + * @brief Funcao para processar o comando 'c'. + */ +void +go_c() +{ + int i; + + getchar(); /* Apanha fim de linha. */ + + printf("cTOT"); + for (i = 0; i < P; i++) + printf(" %.2f", custo_tot(i)); + printf("\n"); + + printf("M"); + for (i = 0; i < P; i++) + printf(" %.2f", margem(i, 0.0)); + printf("\n"); + + printf("cIND"); + for (i = 0; i < P; i++) + printf(" %.2f", custo_ind(i)); + printf("\n"); + + printf("cMPEE"); + for (i = 0; i < P; i++) + printf(" %.2f", custo_mpee(i)); + printf("\n"); +} + +/** + * @brief Funcao para processar o comando 'w'. + */ +void +go_w() +{ + int p; + + scanf("%d", &p); + getchar(); /* Apanha fim de linha. */ + p--; + + printf("W %s A:%.2f B:%.2f C:%.2f D:%.2f E:%.2f F:%.2f\n", + produto[p].nome, + custo_a(), + custo_b(p), + custo_c(p), + custo_d(p), + custo_e(), + custo_f(p)); +} + +/** + * @brief Funcao para processar o comando 't'. + */ +void +go_t() +{ + int i; + double custo = 0.0, venda = 0.0; + + getchar(); /* Apanha fim de linha. */ + + /* Calcular os valores acumulados para as vendas e para os custos + * totais. */ + for (i = 0; i < P; i++) { + custo += custo_tot(i) * produto[i].vendas; + venda += produto[i].pvenda * produto[i].vendas; + } + + printf("T %.2f %.2f %.2f %.2f\n", + custo, + venda, + venda - custo, + (venda - custo) * 100 / venda); +} + +/** + * @brief Funcao para processar o comando 'v'. + */ +void +go_v() +{ + int p; + double d, vd; + + scanf("%d %lf", &p, &d); + getchar(); /* Apanha fim de linha. */ + p--; + + printf("VD %s %.2f %.2f %.2f", + produto[p].nome, + margem(p, 0), + d, + margem(p, d)); + + /* Calcular valor com desconto. */ + vd = produto[p].pvenda * (1 - d/100); + + /* Analise da decisao face ao desconto. */ + if (custo_tot(p) <= vd) + printf(" tot\n"); + else if (custo_ind(p) <= vd) + printf(" ind\n"); + else if (custo_mpee(p) <= vd) + printf(" mpee\n"); + else + printf(" 0\n"); +} + +/** + * @brief Funcao de comparacao para produtos. + * + * Funcao de comapracao para produtos que tem em conta o custo total, + * por ordem crescente, e caso os dois produtos tenham o mesmo custo + * total, tem em conta o seu identificados também por ordem crescente. + * + * @return 0 se os produtos tiverem o mesmo custo total e o mesmo + * identificador, -1 se o custo total do primeiro for menor do que + * o custo total do segundo, ou sendo iguais, se o identificador do + * primeiro for menor do que o do segundo, 1 caso contrario. + */ +static int +pcmp(const void * pa, const void *pb) +{ + int i = * (int *) pa, j = * (int *) pb; + + /* Comparar custos totais. */ + if (custo_tot(i) < custo_tot(j)) + return -1; + + if (custo_tot(i) > custo_tot(j)) + return 1; + + /* Os custos totais sao iguais, comparar identificadores. */ + return i - j; +} + +/** + * @brief Funcao para processar o comando 'x'. + */ +void +go_x() +{ + int choice, tmp[P], i; + + scanf("%d", &choice); + getchar(); /* Apanha fim de linha. */ + + /* Se a escolha e' diferente de 0, entao temos de ordenar. */ + if (choice) { + + /* Preencher vector auxiliar para comparacao indirecta. Na pratica + * vamos estar a ordenar indices do vector dos produtos. */ + for (i = 0; i < P; i++) + tmp[i] = i; + + /* Ordenar com fase na funcao pcmp que implementa os criterios de + * comparacao. */ + qsort(tmp, P, sizeof(int), pcmp); + + /* Imprimir os produtos ordenados. Notar o acesso indirecto ao + * vector com os produtos. */ + for (i = 0; i < P; i++) + printf("%s %.2f\n", produto[tmp[i]].nome, custo_tot(tmp[i])); + } +} + +/** + * @brief Funcao para calcular CUSTO A. + * + * @return valor do CUSTO A + */ +double +custo_a() +{ + int i; + double vendas_total = 0; + + for (i = 0; i < P; i++) + vendas_total += produto[i].vendas; + + return orcamento[0] / vendas_total; +} + +/** + * @brief Funcao para calcular CUSTO B. + * + * @param 'p' identificador/indice do produto + * @return valor do CUSTO B para o produto 'p' + */ +double +custo_b(int p) +{ + int i; + double mo = 0; + + for (i = 0; i < P; i++) + mo += produto[i].k_mo * produto[i].vendas; + + return orcamento[1] * produto[p].k_mo / mo; +} + +/** + * @brief Funcao para calcular CUSTO C. + * + * @param 'p' identificador/indice do produto + * @return valor do CUSTO C para o produto 'p' + */ +double +custo_c(int p) +{ + int i; + double en = 0; + + for (i = 0; i < P; i++) + en += produto[i].k_en * produto[i].vendas; + + return orcamento[2] * produto[p].k_en / en; +} + +/** + * @brief Funcao para calcular CUSTO D. + * + * @param 'p' identificador/indice do produto + * @return valor do CUSTO C para o produto 'p' + */ +double +custo_d(int p) +{ + int i; + double eq = 0; + + for (i = 0; i < P; i++) + eq += produto[i].k_eq * produto[i].vendas; + + return orcamento[3] * produto[p].k_eq / eq; +} + +/** + * @brief Funcao para calcular CUSTO E. + * + * @return valor do CUSTO E + */ +double +custo_e() +{ + int i; + double vendas_total = 0; + + for (i = 0; i < P; i++) + vendas_total += produto[i].vendas; + + return orcamento[4] / vendas_total; +} + +/** + * @brief Funcao para calcular CUSTO F. + * + * @param 'p' identificador/indice do produto + * @return valor do CUSTO F para o produto 'p' + */ +double +custo_f(int p) +{ + int i; + double mat = 0; + + for (i = 0; i < M; i++) + mat += produto[p].m[i] * materia[i].custo; + + return mat / (100 - produto[p].perdas) * 1000; +} + +/** + * @brief Funcao para calcular o custo total + * + * @param 'p' identificador/indice do produto + * @return valor do custo total para o produto 'p' + */ +double +custo_tot(int p) +{ + return custo_a() + custo_b(p) + custo_c(p) + + custo_d(p) + custo_e() + custo_f(p); +} + +/** + * @brief Funcao para calcular o custo indirecto. + * + * @param 'p' identificador/indice do produto + * @return valor do custo indirecto para o produto 'p' + */ +double +custo_ind(int p) +{ + return custo_b(p) + custo_c(p) + custo_d(p) + + custo_e() + custo_f(p); +} + +/** + * @brief Funcao para calcular o custo MPEE. + * + * @param 'p' identificador/indice do produto + * @return valor do custo MPEE para o produto 'p' + */ +double custo_mpee(int p) +{ + return custo_c(p) + custo_e() + custo_f(p); +} + +/** + * @brief Funcao para calcular a margem. + * + * @param 'p' identificador/indice do produto + * @param 'd' desconto em percentagem a aplicar + * @return valor da margem de lucro para o produto 'p' + */ +double margem(int p, double d) +{ + return ((produto[p].pvenda * (1 - d/100)) - custo_tot(p)) * 100 + / (produto[p].pvenda * (1 - d/100)); +} + diff --git a/1314s1p2/binheap.c b/1314s1p2/binheap.c new file mode 100644 index 0000000..e465243 --- /dev/null +++ b/1314s1p2/binheap.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2011, A P Francisco + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include + +#define LEFT(x) ((((x) + 1) << 1) - 1) +#define RIGHT(x) (((x) + 1) << 1) +#define PARENT(x) ((((x) + 1) >> 1) - 1) + +void +binheap_exchange(size_t *heap, size_t *map, size_t i, size_t j) +{ + size_t v; + + assert(map[heap[i]] == i && map[heap[j]] == j); + + map[heap[i]] = j; + map[heap[j]] = i; + v = heap[i]; + heap[i] = heap[j]; + heap[j] = v; + + assert(map[heap[i]] == i && map[heap[j]] == j); +} + +void +binheap_siftdown(void *key, size_t *heap, size_t *map, size_t n, size_t size, + size_t i, int(*cmp)(const void *, const void *)) +{ + size_t l = LEFT(i), r = RIGHT(i), m = i; + + if (l < n && cmp(((char *) key) + heap[l]*size, + ((char *) key) + heap[m]*size) < 0) + m = l; + if (r < n && cmp(((char *) key) + heap[r]*size, + ((char *) key) + heap[m]*size) < 0) + m = r; + if (m == i) return; + binheap_exchange(heap, map, i, m); + binheap_siftdown(key, heap, map, n, size, m, cmp); +} + +void +binheap_siftup(void *key, size_t *heap, size_t *map, size_t n, size_t size, + size_t i, int(*cmp)(const void *, const void *)) +{ + size_t p = PARENT(i); + + if (p >= ULONG_MAX || cmp(((char *) key) + heap[p]*size, + ((char *) key) + heap[i]*size) <= 0) { + return; + } + binheap_exchange(heap, map, i, p); + binheap_siftup(key, heap, map, n, size, p, cmp); +} + +void +binheap_make(void *key, size_t *heap, size_t *map, size_t n, + size_t size, int(*cmp)(const void *, const void *)) +{ + int i; + + for (i = 0; i < n; i++) + heap[i] = map[i] = i; + + for (i = PARENT(n - 1); i >= 0; i--) + binheap_siftdown(key, heap, map, n, size, i, cmp); +} + diff --git a/1314s1p2/binheap.h b/1314s1p2/binheap.h new file mode 100644 index 0000000..061c5d1 --- /dev/null +++ b/1314s1p2/binheap.h @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2013, A P Francisco + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _BINHEAP_H_ +#define _BINHEAP_H_ + +#include +#include +#include + +struct binheap { + size_t size; + size_t max_size; + size_t *heap; + size_t *map; + void *key; + size_t ksz; + int (*cmp)(const void *,const void *); +}; + +#define LEFT(x) ((((x) + 1) << 1) - 1) +#define RIGHT(x) (((x) + 1) << 1) +#define PARENT(x) ((((x) + 1) >> 1) - 1) + +#define BINHEAP_INIT(q, type, k, n, c) do { \ + (q) = malloc(sizeof(struct binheap)); \ + (q)->max_size = (n); \ + (q)->size = 0; \ + (q)->heap = malloc(sizeof(size_t)*(n)); \ + memset((q)->heap, 0xFF, sizeof(size_t)*(n)); \ + (q)->map = malloc(sizeof(size_t)*(n)); \ + memset((q)->map, 0xFF, sizeof(size_t)*(n)); \ + (q)->key = (k); \ + (q)->ksz = sizeof(type); \ + (q)->cmp = (c); \ +} while (/*CONSTCOND*/0) + +#define BINHEAP_FREE(q) do { \ + free((q)->heap); \ + free((q)->map); \ + free(q); \ +} while (/*CONSTCOND*/0) + +#define BINHEAP_EMPTY(q) ((q)->size == 0) +#define BINHEAP_HAS(q, id) ((q)->map[id] < (q)->size) +#define BINHEAP_TOP(q) ((q)->heap[0]) + +#define BINHEAP_RESET(q) do { \ + (q)->size = 0; \ + memset((q)->heap, 0xFF, sizeof(size_t)*(q)->max_size); \ + memset((q)->map, 0xFF, sizeof(size_t)*(q)->max_size); \ +} while (/*CONSTCOND*/0) + +#define BINHEAP_PUSH(q, id) do { \ + if ((q)->map[id] >= ULONG_MAX) { \ + if ((q)->size >= (q)->max_size) \ + abort(); \ + \ + (q)->map[id] = (q)->size; \ + (q)->heap[(q)->size] = (id); \ + (q)->size ++; \ + } \ + binheap_siftup((q)->key, (q)->heap, (q)->map, (q)->size, \ + (q)->ksz, (q)->map[id], (q)->cmp); \ + binheap_siftdown((q)->key, (q)->heap, (q)->map, (q)->size, \ + (q)->ksz, (q)->map[id], (q)->cmp); \ +} while (/*CONSTCOND*/0) + +#define BINHEAP_UPDATE(q, id) BINHEAP_PUSH(q, id) + +#define BINHEAP_DEL(q, id) do { \ + register size_t aux = (q)->map[id]; \ + q->size--; \ + if (q->size != aux) { \ + binheap_exchange((q)->heap, (q)->map, (q)->size, aux); \ + binheap_siftup((q)->key, (q)->heap, (q)->map, (q)->size, \ + (q)->ksz, aux, (q)->cmp); \ + binheap_siftdown((q)->key, (q)->heap, (q)->map, (q)->size, \ + (q)->ksz, aux, (q)->cmp); \ + } \ + q->heap[q->size] = ULONG_MAX; \ + q->map[id] = ULONG_MAX; \ +} while (/*CONSTCOND*/0) + +#define BINHEAP_POP(q) do { \ + register size_t aux = q->heap[0]; \ + q->size--; \ + binheap_exchange((q)->heap, (q)->map, (q)->size, 0); \ + binheap_siftdown((q)->key, (q)->heap, (q)->map, (q)->size, \ + (q)->ksz, 0, (q)->cmp); \ + q->heap[q->size] = ULONG_MAX; \ + q->map[aux] = ULONG_MAX; \ +} while (/*CONSTCOND*/0) + +#define BINHEAP_MAKE(q, n) do { \ + (q)->size = (n); \ + binheap_make((q)->key, (q)->heap, (q)->map, \ + (q)->size, (q)->ksz, (q)->cmp); \ +} while (/*CONSTCOND*/0) + +void binheap_exchange(size_t *heap, size_t *map, size_t i, size_t j); + +void binheap_make(void *key, size_t *heap, size_t *map, size_t n, + size_t size, int(*cmp)(const void *, const void *)); + +void binheap_siftdown(void *key, size_t *heap, size_t *map, size_t n, + size_t size, size_t i, int(*cmp)(const void *, const void *)); + +void binheap_siftup(void *key, size_t *heap, size_t *map, size_t n, + size_t size, size_t i, int(*cmp)(const void *, const void *)); + +#endif /* _BINHEAP_H_ */ diff --git a/1314s1p2/hash.c b/1314s1p2/hash.c new file mode 100644 index 0000000..647364b --- /dev/null +++ b/1314s1p2/hash.c @@ -0,0 +1,155 @@ +/** + * @file hash.c + * @brief Implementacao basica de uma tabela de dispersao com + * resolucao por encadeamento linear. + */ +#include +#include + +#include "hash.h" + +/* Lista de primos auxiliar, tem de ser aumentada se precisarmos de + * guardar mais elementos. */ +#define PRIMES 7 +static int primes[PRIMES] = {16127, 34651, 68111, 131071, 260999, 524287, 999983}; + +/** + * @brief Estrutura que representa a tabela de dispersao. + */ +struct SThash_s { + int N, M, p; + int (*hash)(const void *, int M); + void ** tab; +}; + +/** + * @brief Funcao que inicializa uma tabela de dispersao. + * + * @param 'hash' identifica a funcao de dispersao a utilizar nesta + * tabela de dispersao. + * @return Uma tabela de dispersao. + */ +SThash +STinit(int (*hash)(const void *, int M)) +{ + SThash st = malloc(sizeof(struct SThash_s)); + + st->N = st->p = 0; + st->M = primes[st->p]; + st->hash = hash; + + st->tab = malloc(st->M*sizeof(void *)); + memset(st->tab, 0x0, st->M*sizeof(void *)); + + return st; +} + +/** + * @brief Funcao que liberta a memoria associada a uma tabela de + * dipersao. + * + * @param 'h' identifica a tabela de dispersao a libertar. + */ +void +STfree(SThash h) +{ + free(h->tab); + free(h); +} + +/** + * @brief Funcao para procurar numa tabela de dispersao. + * + * @para 'h' identifica a tabela onde procurar. + * @param 'item' identifica o elemento a procurar. + * @param 'cmp' identifica a funcao de comparacao a utilizar. + * + * @return O elemento se existir, NULL caso contrario. + */ +void * +STsearch(SThash h, void * item, int (*cmp)(const void *, const void *)) +{ + int i = h->hash(item, h->M); + + while (h->tab[i] != NULL) + if (cmp(item, h->tab[i]) == 0) + return h->tab[i]; + else + i = (i+1) % h->M; + + return NULL; +} + +/** + * @brief Funcao para apagar numa tabela de dispersao. + * + * @para 'h' identifica a tabela onde apagar. + * @param 'item' identifica o elemento a apagar. + * @param 'cmp' identifica a funcao de comparacao a utilizar. + */ +void +STdelete(SThash h, void * item, int (*cmp)(const void *, const void *)) +{ + int j, i = h->hash(item, h->M); + void * v; + + while (h->tab[i] != NULL) + if (cmp(item, h->tab[i]) == 0) + break; + else + i = (i+1) % h->M; + + if (h->tab[i] == NULL) return; + + h->tab[i] = NULL; + + h->N--; + for (j = (i+1) % h->M; h->tab[j] != NULL; j = (j+1) % h->M, h->N--) { + v = h->tab[j]; + h->tab[j] = NULL; + STinsert(h, v); + } +} + +/** + * Funcao auxiliar que permitir aumentar o tamanho da tabela. Se nao + * for possivel (ver lista de primos em cima), o programa termina de + * imediato. + */ +static void +STexpand(SThash h) { + int i; + void **t = h->tab; + + if (++(h->p) >= PRIMES) + exit(1); + + h->N = 0; + h->M = primes[h->p]; + h->tab = malloc(h->M*sizeof(void *)); + memset(h->tab, 0x0, h->M*sizeof(void *)); + for (i = 0; i < primes[h->p - 1]; i++) + if (t[i] != NULL) + STinsert(h, t[i]); + free(t); +} + +/** + * @brief Funcao para inserir numa tabela de dispersao. + * + * @para 'h' identifica a tabela onde inserir. + * @param 'item' identifica o elemento a inserir. + */ +void +STinsert(SThash h, void * item) { + int i = h->hash(item, h->M); + + while (h->tab[i] != NULL) + i = (i+1) % h->M; + + h->tab[i] = item; + + if (h->N++ > 0.6*h->M) + STexpand(h); +} + diff --git a/1314s1p2/hash.h b/1314s1p2/hash.h new file mode 100644 index 0000000..4f3d46d --- /dev/null +++ b/1314s1p2/hash.h @@ -0,0 +1,19 @@ +/** + * @file hash.h + * @brief Implementacao basica de uma tabela de dispersao com + * resolucao por encadeamento linear. + */ +#ifndef HASH_H +#define HASH_H + +typedef struct SThash_s * SThash; + +SThash STinit(int (*hash)(const void *, int M)); +void STfree(SThash h); + +void * STsearch(SThash h, void * item, int (*cmp)(const void *, const void *)); + +void STdelete(SThash h, void * item, int (*cmp)(const void *, const void *)); +void STinsert(SThash h, void * item); + +#endif diff --git a/1314s1p2/list.c b/1314s1p2/list.c new file mode 100644 index 0000000..2dd3490 --- /dev/null +++ b/1314s1p2/list.c @@ -0,0 +1,84 @@ +/** + * @file list.c + * @brief Implementacao basica de uma lista circular. + */ +#include + +#include "list.h" + +/** + * @brief Funcao para insercao. + * + * @param 'head' identifica a cabeca da lista onde inserir. + * @param 'value' identifica o valor a inserir. + */ +void +list_insert(link head, void * value) +{ + link node = (link) malloc(sizeof(struct node)); + node->value = value; + node->next = head; + node->prev = head->prev; + head->prev->next = node; + head->prev = node; +} + +/** + * @brief Funcao para mover um no' entre listas. + * + * ATENCAO: Nao verifica se o no' ja' faz parte da lista! + * + * @param 'head' identifica a cabeca da lista onde mover. + * @param 'node' identifica o no' a mover. + */ +void +list_move(link head, link node) +{ + /* Remove */ + node->prev->next = node->next; + node->next->prev = node->prev; + + /* Add */ + node->next = head; + node->prev = head->prev; + head->prev->next = node; + head->prev = node; +} + +/** + * @brief Funcao para remover um no' da lista. + * + * Neste caso nao e' necessaria a cabeca da lista uma vez que estamos + * a utilizar listas duplamente ligadas. + * + * @param 'node' identifica o no' a mover. + */ +void +list_delete(link node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; + free(node); +} + +/** + * @brief Funcao para libertar a memoria associada a uma lista. + * + * @param 'head' identifica a cabeca da lista a libertar. + * @param 'freevalue' identifica a funcao que liberta a memoria + * associada aos valores (pode ser NULL). + */ +void +list_free(link head, void (*freevalue)(void *)) +{ + link l = head->next, aux; + + while (l != head) { + if (freevalue) + (*freevalue)(l->value); + aux = l; + l = l->next; + free(aux); + } +} + diff --git a/1314s1p2/list.h b/1314s1p2/list.h new file mode 100644 index 0000000..a31db65 --- /dev/null +++ b/1314s1p2/list.h @@ -0,0 +1,20 @@ +/** + * @file list.h + * @brief Implementacao basica de uma lista circular. + */ +#ifndef LIST_H +#define LIST_H + +typedef struct node *link; + +struct node { + void * value; + struct node *next, *prev; +}; + +void list_insert(link head, void * value); +void list_move(link head, link node); +void list_delete(link node); +void list_free(link head, void (*freevalue)(void *)); + +#endif diff --git a/1314s1p2/proj2.c b/1314s1p2/proj2.c new file mode 100644 index 0000000..49abc55 --- /dev/null +++ b/1314s1p2/proj2.c @@ -0,0 +1,250 @@ +/** + * @file proj2.c + * @brief Implementacao do segundo projecto de IAED: + */ +#include +#include +#include + +#include "list.h" +#include "hash.h" + +#define NPKG 5 +#define MINC 128 + +/** + * @brief Estrutura que representa uma chamada. + */ +struct call { + unsigned long nr; + char *name, pkg; +}; + +/** + * Variaveis locais ao programa. A fila de prioridades e' representada + * por pq e consiste em NPKG listas ligadas. Utilizamos duas tabelas + * de dispersao, namehash e nrhash, respectivamente indexadas por nome + * e numero, para acelerar a procura nas listas. + */ +static struct node pq[NPKG]; +static SThash namehash; +static SThash nrhash; + +/** + * Funcao para libertar a memoria associada a uma chamada. + */ +static void +free_call(void * c) { + free(((struct call *) c)->name); + free(c); +} + +/** + * Funcao auxiliar para ler nomes (ilimitados). + */ +static char * +readname() +{ + size_t size = 0, i = 0; + char * name = NULL, c; + + while ((c = getchar()) != ' ' && c != '\n') { + /* Verificar se existe ainda espaco livre. */ + if (i >= size) { + size += MINC; + name = realloc(name, sizeof(char)*(size+1)); + } + + name[i++] = c; + } + name[i++] = '\0'; + /* name = realloc(name, i*sizeof(char)); */ + + return name; +} + +/** + * Funcao que compara dois nos das listas com base no numero de + * cliente associado. + */ +static int +nrcmp(const void *pa, const void *pb) +{ + struct call * la = (struct call *) ((link) pa)->value; + struct call * lb = (struct call *) ((link) pb)->value; + + if (la->nr < lb->nr) + return -1; + if (la->nr > lb->nr) + return 1; + return 0; +} + +/** + * Funcao que compara dois nos das listas com base no nome de + * cliente associado. + */ +static int +namecmp(const void *pa, const void *pb) +{ + struct call * la = (struct call *) ((link) pa)->value; + struct call * lb = (struct call *) ((link) pb)->value; + + return strcmp(la->name, lb->name); +} + +/** + * Funcao de dispersao para os nos das listas com base no numero de + * cliente associado. + */ +static int +nrhashfun(const void *p, int M) +{ + return ((struct call *) ((link) p)->value)->nr % M; +} + +/** + * Funcao de dispersao para os nos das listas com base no nome de + * cliente associado. + */ +static int +namehashfun(const void *p, int M) +{ + char * v = ((struct call *) ((link) p)->value)->name; + int h = 0, a = 127; + + for (; *v != '\0'; v++) + h = (a*h + *v) % M; + return h; +} + +/** + * @brief Funcao main. + * + * @return Codigo de estado de saida do programa. + */ +int +main(int argc, char * argv[]) +{ + char cmd; + struct call * c, ctmp; + struct node ntmp; + link ltmp; + size_t i; + + /* Inicializacao das filas e das tabelas de dispersao. */ + memset(pq, 0x0, sizeof(struct node)*NPKG); + for (i = 0; i < NPKG; i++) + pq[i].next = pq[i].prev = &pq[i]; + namehash = STinit(namehashfun); + nrhash = STinit(nrhashfun); + + /* Processar comando. */ + while ((cmd = getchar()) != 'x') { + switch (cmd) { + case 'a': + /* Nova chamada. */ + c = malloc(sizeof(struct call)); + getchar(); /* catch ' ' */ + c->name = readname(); + scanf("%lu", &c->nr); + scanf(" %c", &c->pkg); + + getchar(); /* catch '\n' */ + + /* Inserir chamada na fila de espera. */ + list_insert(&pq[c->pkg - 'A'], c); + + /* Indexar o novo no adicionado 'a fila (lista duplamente + * ligada). */ + STinsert(namehash, pq[c->pkg - 'A'].prev); + STinsert(nrhash, pq[c->pkg - 'A'].prev); + break; + case 'u': + /* Identificar cliente e guardar numa estrutura temporaria. */ + scanf("%lu", &ctmp.nr); + scanf(" %c", &ctmp.pkg); + + getchar(); /* catch '\n' */ + + /* Guardar chamada temporaria num no' tambem temporario. */ + ntmp.value = &ctmp; + + /* Procurar no' na tabela indexada por numero. */ + ltmp = (link) STsearch(nrhash, &ntmp, nrcmp); + + /* Verificar se existe de facto alteracao. */ + if (ctmp.pkg != ((struct call *) ltmp->value)->pkg) { + + /* Actualizar pacote. */ + c = (struct call *) ltmp->value; + ((struct call *) ltmp->value)->pkg = ctmp.pkg; + + /* Mover no' entre as filas. */ + list_move(&pq[c->pkg - 'A'], ltmp); + } + break; + case 'l': + getchar(); /* catch '\n' */ + + /* Procurar proxima chamda. */ + for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++); + + /* Se existir, imprimir informacao. */ + if (i < NPKG) { + c = (struct call *) pq[i].next->value; + printf("%s %lu %c\n", c->name, c->nr, c->pkg); + } else /* NA caso contrario. */ + printf("NA\n"); + break; + case 'p': + getchar(); /* catch '\n' */ + /* Procurar proxima chamada. */ + for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++); + + /* Se existir, imprimir e apagar a chamada. */ + if (i < NPKG) { + c = (struct call *) pq[i].next->value; + printf("%s %lu %c\n", c->name, c->nr, c->pkg); + + /* Apagar em ambas as tabelas e na fila. */ + STdelete(namehash, pq[i].next, namecmp); + STdelete(nrhash, pq[i].next, nrcmp); + list_delete(pq[i].next); + + /* Libertar memoria associada 'a chamada. */ + free_call(c); + } else /* NA caso contrario. */ + printf("NA\n"); + break; + case 'r': + getchar(); /* catch ' ' */ + + /* Identificar cliente e guardar em estruturas temporarias. */ + ctmp.name = readname(); + ntmp.value = &ctmp; + + /* Procurar no' na tabela indexada por nome. */ + ltmp = (link) STsearch(namehash, &ntmp, namecmp); + c = (struct call *) ltmp->value; + + /* Apagar em ambas as tabelas e na fila. */ + STdelete(namehash, ltmp, namecmp); + STdelete(nrhash, ltmp, nrcmp); + list_delete(ltmp); + + /* Libertar memoria associada 'a chamada e ao nome temporario. */ + free_call(c); + free(ctmp.name); + } + } + + /* Libertar a memoria ainda alocada. */ + STfree(namehash); + STfree(nrhash); + for (i = 0; i < NPKG; i++) + list_free(&pq[i], free_call); + + return EXIT_SUCCESS; +} + diff --git a/1314s1p2/proj2alt.c b/1314s1p2/proj2alt.c new file mode 100644 index 0000000..bcb3ba4 --- /dev/null +++ b/1314s1p2/proj2alt.c @@ -0,0 +1,152 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "list.h" + +#define NPKG 5 +#define MINC 128 + +struct call { + unsigned long nr; + char *name, pkg; +}; + +static struct node pq[NPKG]; +static void * nameroot; +static void * nrroot; + +static void +free_call(void * c) { + free(((struct call *) c)->name); + free(c); +} + +static void do_nothing(void * n) { } + +static char * +readname() +{ + size_t size = MINC, i = 0; + char * name = malloc(sizeof(char)*MINC), c; + + while ((c = getchar()) != ' ' && c != '\n') { + if (i >= size - 1) { + size += MINC; + name = realloc(name, sizeof(char)*size); + } + name[i++] = c; + } + name[i] = '\0'; + + return name; +} + +static int +nrcmp (const void *pa, const void *pb) +{ + struct call * la = (struct call *) ((link) pa)->value; + struct call * lb = (struct call *) ((link) pb)->value; + + if (la->nr < lb->nr) + return -1; + if (la->nr > lb->nr) + return 1; + return 0; +} + +static int +namecmp(const void *pa, const void *pb) +{ + struct call * la = (struct call *) ((link) pa)->value; + struct call * lb = (struct call *) ((link) pb)->value; + + return strcmp(la->name, lb->name); +} + +int +main(int argc, char * argv[]) +{ + char cmd; + struct call * c, ctmp; + struct node ntmp; + link ltmp; + size_t i; + + memset(pq, 0x0, sizeof(struct node)*NPKG); + for (i = 0; i < NPKG; i++) + pq[i].next = pq[i].prev = &pq[i]; + nameroot = nrroot = NULL; + + while ((cmd = getchar()) != 'x') { + switch (cmd) { + case 'a': + c = malloc(sizeof(struct call)); + getchar(); /* catch ' ' */ + c->name = readname(); + scanf("%lu", &c->nr); + scanf(" %c", &c->pkg); + getchar(); /* catch '\n' */ + list_insert(&pq[c->pkg - 'A'], c); + tsearch(pq[c->pkg - 'A'].prev, &nameroot, namecmp); + tsearch(pq[c->pkg - 'A'].prev, &nrroot, nrcmp); + break; + case 'u': + scanf("%lu", &ctmp.nr); + scanf(" %c", &ctmp.pkg); + getchar(); /* catch '\n' */ + ntmp.value = &ctmp; + ltmp = *((link*) tfind(&ntmp, &nrroot, nrcmp)); + if (ctmp.pkg != ((struct call *) ltmp->value)->pkg) { + c = (struct call *) ltmp->value; + ((struct call *) ltmp->value)->pkg = ctmp.pkg; + list_move(&pq[c->pkg - 'A'], ltmp); + } + break; + case 'l': + getchar(); /* catch '\n' */ + for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++); + if (i < NPKG) { + c = (struct call *) pq[i].next->value; + printf("%s %lu %c\n", c->name, c->nr, c->pkg); + } else + printf("NA\n"); + break; + case 'p': + getchar(); /* catch '\n' */ + for (i = 0; i < NPKG && pq[i].next == &pq[i]; i++); + if (i < NPKG) { + c = (struct call *) pq[i].next->value; + printf("%s %lu %c\n", c->name, c->nr, c->pkg); + tdelete(pq[i].next, &nameroot, namecmp); + tdelete(pq[i].next, &nrroot, nrcmp); + list_delete(pq[i].next); + free_call(c); + } else + printf("NA\n"); + break; + case 'r': + getchar(); /* catch ' ' */ + ctmp.name = readname(); + ntmp.value = &ctmp; + /*fprintf(stderr, "ERROR: %s\n", ctmp.name);*/ + ltmp = *((link *) tfind(&ntmp, &nameroot, namecmp)); + c = (struct call *) ltmp->value; + tdelete(ltmp, &nameroot, namecmp); + tdelete(ltmp, &nrroot, nrcmp); + list_delete(ltmp); + free_call(c); + free(ctmp.name); + } + } + + tdestroy(nameroot, do_nothing); + tdestroy(nrroot, do_nothing); + for (i = 0; i < NPKG; i++) + list_free(&pq[i], free_call); + + return EXIT_SUCCESS; +} + diff --git a/1314s1p2/proj2gen.c b/1314s1p2/proj2gen.c new file mode 100644 index 0000000..fc3c8a2 --- /dev/null +++ b/1314s1p2/proj2gen.c @@ -0,0 +1,228 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#include "binheap.h" + +#define MAXNAME 64 +#define MAXNUM 1000000000 +#define MAXPKG 5 + +struct call { + unsigned long nr; + size_t time; + char *name, pkg; +}; + +static int alpha[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '_', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; + +static struct call ** store; +static size_t storei, time; +static struct binheap * q; +static void * nameroot; +static void * nrroot; + +static void do_nothing(void * n) { } + +void +*genname() +{ + size_t len = rand()%MAXNAME + 1, i; + char * name = malloc(sizeof(char)*(len+1)); + + name[0] = alpha[rand()%52]; + for (i = 1; i < len; i++) + name[i] = alpha[rand()%63]; + name[i] = '\0'; + + return name; +} + +unsigned long +gennum() +{ + return rand()%MAXNUM; +} + +char +genpkg() +{ + return 'A' + rand()%MAXPKG; +} + +int +callcmp(const void *ap, const void *bp) +{ + struct call * a = * (struct call **) ap; + struct call * b = * (struct call **) bp; + + if (a->pkg < b->pkg) + return -1; + if (a->pkg > b->pkg) + return 1; + + return a->time - b->time; +} + +static int +nrcmp (const void *pa, const void *pb) +{ + unsigned long la = (unsigned long) pa; + unsigned long lb = (unsigned long) pb; + + if (la < lb) + return -1; + if (la > lb) + return 1; + return 0; +} + +static int +namecmp (const void *pa, const void *pb) +{ + return strcmp((char *) pa, (char *) pb); +} + +int +main(int argc, char * argv[]) +{ + struct call * c; + int i, k, n, op, maxop; + char pkg; + + if (argc != 4) { + fprintf(stderr, "Usage: %s \nseed\tsemente para o srand\nsize\ttamanho do teste\nmaxop\toperacoes a considerar, valores possiveis: 1, 2, 3, 4, 5\n", argv[0]); + return EXIT_FAILURE; + } + srand(atoi(argv[1])); + k = atoi(argv[2]); + maxop = atoi(argv[3]); + + store = malloc(sizeof(struct call *)*2*k); + memset(store, 0x0, sizeof(struct call *)*2*k); + storei = time = 0; + nameroot = nrroot = NULL; + + for (i = 0; i < k; i++) { + c = malloc(sizeof(struct call)); + c->name = genname(); + while (tfind(c->name, &nameroot, namecmp)) { + free(c->name); + c->name = genname(); + } + tsearch(c->name, &nameroot, namecmp); + + c->nr = gennum(); + while (tfind((void *) c->nr, &nrroot, nrcmp)) + c->nr = gennum(); + tsearch((void *) c->nr, &nrroot, nrcmp); + + c->pkg = genpkg(); + c->time = time ++; + printf("a %s %lu %c\n", c->name, c->nr, c->pkg); + store[storei++] = c; + } + + assert(k == storei); + + BINHEAP_INIT(q, struct call *, store, 2*k, callcmp); + BINHEAP_MAKE(q, k); + assert(q->size == storei); + + for (i = 0; i < k; i++) { + op = rand()%maxop; + + switch (op) { + case 0: + c = malloc(sizeof(struct call)); + c->name = genname(); + while (tfind(c->name, &nameroot, namecmp)) { + free(c->name); + c->name = genname(); + } + tsearch(c->name, &nameroot, namecmp); + + c->nr = gennum(); + while (tfind((void *) c->nr, &nrroot, nrcmp)) + c->nr = gennum(); + tsearch((void *) c->nr, &nrroot, nrcmp); + + c->pkg = genpkg(); + c->time = time ++; + printf("a %s %lu %c\n", c->name, c->nr, c->pkg); + store[storei++] = c; + + BINHEAP_UPDATE(q, storei-1); + assert(q->size == storei); + break; + case 1: + printf("l\n"); + break; + case 2: + printf("p\n"); + n = BINHEAP_TOP(q); + BINHEAP_POP(q); + /* printf("\t%s %lu %c (%lu)\n", store[n]->name, store[n]->nr, store[n]->pkg, store[n]->time); */ + tdelete(store[n]->name, &nameroot, namecmp); + tdelete((void *) store[n]->nr, &nrroot, nrcmp); + free(store[n]->name); + free(store[n]); + store[n] = NULL; + storei--; + if (storei != n) { + BINHEAP_DEL(q, storei); + store[n] = store[storei]; + store[storei] = NULL; + BINHEAP_UPDATE(q, n); + } + assert(q->size == storei); + break; + case 3: + n = rand()%storei; + pkg = genpkg(); + if (pkg != store[n]->pkg) { + store[n]->pkg = pkg; + store[n]->time = time ++; + printf("u %lu %c\n", store[n]->nr, store[n]->pkg); + BINHEAP_UPDATE(q, n); + assert(q->size == storei); + } + break; + case 4: + n = rand()%storei; + printf("r %s\n", store[n]->name); + BINHEAP_DEL(q, n); + tdelete(store[n]->name, &nameroot, namecmp); + tdelete((void *) store[n]->nr, &nrroot, nrcmp); + free(store[n]->name); + free(store[n]); + storei--; + if (storei != n) { + BINHEAP_DEL(q, storei); + store[n] = store[storei]; + store[storei] = NULL; + BINHEAP_UPDATE(q, n); + } + assert(q->size == storei); + break; + } + } + + printf("x\n"); + + BINHEAP_FREE(q); + for (i = 0; i < storei; i++) { + free(store[i]->name); + free(store[i]); + } + free(store); + tdestroy(nameroot, do_nothing); + tdestroy(nrroot, do_nothing); + + return EXIT_SUCCESS; +} +