]> web.ist.utl.pt Git - iaed.git/commitdiff
Add projects for 2013/14 s1.
authorAlexandre P Francisco <aplf@tecnico.pt>
Tue, 16 Feb 2016 18:50:13 +0000 (18:50 +0000)
committerAlexandre P Francisco <aplf@tecnico.pt>
Tue, 16 Feb 2016 18:50:13 +0000 (18:50 +0000)
1314s1p1.c [new file with mode: 0644]
1314s1p2/binheap.c [new file with mode: 0644]
1314s1p2/binheap.h [new file with mode: 0644]
1314s1p2/hash.c [new file with mode: 0644]
1314s1p2/hash.h [new file with mode: 0644]
1314s1p2/list.c [new file with mode: 0644]
1314s1p2/list.h [new file with mode: 0644]
1314s1p2/proj2.c [new file with mode: 0644]
1314s1p2/proj2alt.c [new file with mode: 0644]
1314s1p2/proj2gen.c [new file with mode: 0644]

diff --git a/1314s1p1.c b/1314s1p1.c
new file mode 100644 (file)
index 0000000..9ccebc8
--- /dev/null
@@ -0,0 +1,647 @@
+/**
+ * @file proj1.c
+ * @brief Implementacao do primeiro projecto de IAED.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#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 (file)
index 0000000..e465243
--- /dev/null
@@ -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 <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+#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 (file)
index 0000000..061c5d1
--- /dev/null
@@ -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 <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 (file)
index 0000000..647364b
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * @file hash.c
+ * @brief Implementacao basica de uma tabela de dispersao com
+ *        resolucao por encadeamento linear.
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#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 (file)
index 0000000..4f3d46d
--- /dev/null
@@ -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 (file)
index 0000000..2dd3490
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * @file list.c
+ * @brief Implementacao basica de uma lista circular.
+ */
+#include <stdlib.h>
+
+#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 (file)
index 0000000..a31db65
--- /dev/null
@@ -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 (file)
index 0000000..49abc55
--- /dev/null
@@ -0,0 +1,250 @@
+/**
+ * @file proj2.c
+ * @brief Implementacao do segundo projecto de IAED:
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 (file)
index 0000000..bcb3ba4
--- /dev/null
@@ -0,0 +1,152 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+
+#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 (file)
index 0000000..fc3c8a2
--- /dev/null
@@ -0,0 +1,228 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+
+#include <assert.h>
+
+#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 <seed> <size> <maxop>\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;
+}
+