diff --git a/2ano/1semestre/aed/teoricas/AED_2022.pdf b/2ano/1semestre/aed/teoricas/AED_2022.pdf new file mode 100644 index 0000000..5f9f1ea Binary files /dev/null and b/2ano/1semestre/aed/teoricas/AED_2022.pdf differ diff --git a/2ano/1semestre/aed/teoricas/README.md b/2ano/1semestre/aed/teoricas/README.md index a6bc33e..273c986 100644 --- a/2ano/1semestre/aed/teoricas/README.md +++ b/2ano/1semestre/aed/teoricas/README.md @@ -14,6 +14,9 @@ | [06](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema06) | Tipos Abstratos | | [07](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema07) | Listas Ligadas | | [08](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema08) | Árvores Binárias | +| [09](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema09) | Dicionários | +| [10](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema10) | Grafos | +| [11](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema11) | C++ | --- *Pode conter erros, caso encontre algum, crie um* [*ticket*](https://github.com/TiagoRG/uaveiro-leci/issues/new) diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV.pdf b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV.pdf new file mode 100644 index 0000000..11c9e3e Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeap.c b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeap.c new file mode 100644 index 0000000..dc1e6e6 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeap.c @@ -0,0 +1,184 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira / Joao Manuel Rodrigues +// +// Binary Max Heap storing pointers to generic items. +// + +#include "MaxHeap.h" + +#include +#include +#include + +// +// A binary or 2-way heap is a complete tree stored in an array. +// +// +-------------------------------------------------------------------------------+ +// | 0 | +// +---------------------------------------+---------------------------------------+ +// | 1 | 2 | +// +-------------------+-------------------+-------------------+-------------------+ +// | 3 | 4 | 5 | 6 | +// +---------+---------+---------+---------+---------+---------+---------+---------+ +// | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 +// | +// +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +// | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | +// 30 | +// +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +// +// The children of node k, if any, are 2*k+1 and 2*k+2. +// +// The value of each node cannot be SMALLER that those of its children. +// + +// The heap data structure +struct _Heap { + void** array; + int capacity; + int size; + compFunc compare; + printFunc print; +}; + +MaxHeap* MaxHeapCreate(int capacity, compFunc compF, printFunc printF) { + MaxHeap* h = (MaxHeap*)malloc(sizeof(MaxHeap)); // alloc heap header + if (h == NULL) abort(); + h->array = (void**)malloc(capacity * sizeof(void*)); // alloc array + if (h->array == NULL) { + free(h); + abort(); + } + h->capacity = capacity; + h->size = 0; + h->compare = compF; + h->print = printF; + return h; +} + +void MaxHeapDestroy(MaxHeap** pph) { + MaxHeap* ph = *pph; + if (ph == NULL) return; + free(ph->array); + free(ph); + *pph = NULL; +} + +int MaxHeapCapacity(const MaxHeap* ph) { return ph->capacity; } + +int MaxHeapSize(const MaxHeap* ph) { return ph->size; } + +int MaxHeapIsEmpty(const MaxHeap* ph) { return ph->size == 0; } + +int MaxHeapIsFull(const MaxHeap* ph) { return ph->size == ph->capacity; } + +void* MaxHeapGetMax(const MaxHeap* ph) { + assert(!MaxHeapIsEmpty(ph)); + return ph->array[0]; +} + +// Internal functions + +// n is the index of a node (n in [0, size[). +// _child(n, 1) is the index of the first child of node n, if < size. +// _child(n, 2) is the index of the second child of node n, if < size. +static inline int _child(int n, int c) { return 2 * n + c; } + +// _parent(n) is the index of the parent node of node n, if n>0. +static inline int _parent(int n) { + assert(n > 0); + return (n - 1) / 2; +} + +// Insert the item into the heap +void MaxHeapInsert(MaxHeap* ph, void* item) { + assert(!MaxHeapIsFull(ph)); + // start at the first vacant spot (just after the last occupied node) + int n = ph->size; + while (n > 0) { + int p = _parent(n); + + // if item not larger than _parent, then we've found the right spot! + if (ph->compare(item, ph->array[p]) <= 0) break; + + // otherwise, move down the item at node p to open up space for new item + ph->array[n] = ph->array[p]; + + // update + n = p; // p is the new vacant spot + } + ph->array[n] = item; // store item at node n + ph->size++; +} + +// Remove the Max item +void MaxHeapRemoveMax(MaxHeap* ph) { + assert(!MaxHeapIsEmpty(ph)); + + ph->size--; // NOTE: we're decreasing the size first! + int n = 0; // the just emptied spot... must fill it with largest child + while (1) { + // index of first child + int max = _child(n, 1); // first child (might not exist) + + if (!(max < ph->size)) break; // if no second child, stop looking + + // if second child is larger, choose it + if (ph->compare(ph->array[max + 1], ph->array[max]) > 0) { + max = max + 1; + } + + // if largest child is not larger than last, stop looking + if (!(ph->compare(ph->array[max], ph->array[ph->size]) > 0)) break; + + // move largest child to fill empty _parent spot + ph->array[n] = ph->array[max]; + + n = max; // now, the largest child spot was just emptied! + } + + // move last element to emptied spot + ph->array[n] = ph->array[ph->size]; + + // mark last element as vacant + ph->array[ph->size] = NULL; +} + +// Check the (max-)heap property (the heap invariant): +// Each node must be >= than each of its children. +// Equivalently (but easier): +// Each node must be <= its parent. +int MaxHeapCheck(const MaxHeap* ph) { + // For each node other than root: compare with its parent + for (int n = 1; n < ph->size; n++) { + int p = _parent(n); + if (ph->compare(ph->array[n], ph->array[p]) > 0) return 0; + } + return 1; +} + +// Visualize the heap items as a tree +static void _HeapView(const MaxHeap* ph, int level, const char* edge, + int root) { + if (root < ph->size) { + _HeapView(ph, level + 1, "/", _child(root, 1)); + printf("%*s", 4 * level, edge); + ph->print(ph->array[root]); + printf("\n"); + _HeapView(ph, level + 1, "\\", _child(root, 2)); + } +} + +// Visualize the heap both as a tree and as an array. +void MaxHeapView(const MaxHeap* ph) { + printf("tree:\n"); + _HeapView(ph, 0, ":", 0); // : marks the root + printf("array:"); + for (int i = 0; i < ph->size; i++) { + printf(" "); + ph->print(ph->array[i]); + } + printf("\nsize: %d\n", ph->size); +} diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeap.h b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeap.h new file mode 100644 index 0000000..af9d1fe --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeap.h @@ -0,0 +1,51 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira / Joao Manuel Rodrigues +// +// Binary Max Heap storing pointers to generic items. +// + +#ifndef _MAX_HEAP_ +#define _MAX_HEAP_ + +// The type for MaxHeap instances +typedef struct _Heap MaxHeap; + +// The type for item comparator functions +typedef int (*compFunc)(const void* p1, const void* p2); + +// The type for item printer functions +typedef void (*printFunc)(void* p); + +// CREATE/DESTROY + +MaxHeap* MaxHeapCreate(int capacity, compFunc compF, printFunc printF); + +void MaxHeapDestroy(MaxHeap** pph); + +// GETTERS + +int MaxHeapCapacity(const MaxHeap* ph); + +int MaxHeapSize(const MaxHeap* ph); + +int MaxHeapIsEmpty(const MaxHeap* ph); + +int MaxHeapIsFull(const MaxHeap* ph); + +void* MaxHeapGetMax(const MaxHeap* ph); + +// MODIFY + +void MaxHeapInsert(MaxHeap* ph, void* item); + +void MaxHeapRemoveMax(MaxHeap* ph); + +// CHECK/VIEW + +int MaxHeapCheck(const MaxHeap* ph); + +void MaxHeapView(const MaxHeap* ph); + +#endif diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeapTest.c b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeapTest.c new file mode 100644 index 0000000..ce34866 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/01_Example_MAX_HEAP/MaxHeapTest.c @@ -0,0 +1,91 @@ +// +// João Manuel Rodrigues, AlgC, May 2020 +// Joaquim Madeira, AlgC, May 2020 +// +// TESTING the TAD MaxHeap implementation +// + +// This program accepts multiple arguments. +// If the argument is: +// a number : it is inserted into a max-heap. +// - : the first (maximum) item is removed from the head +// ? : the heap content is shown, both in tree form and array form. + +// Try the arguments below. + +// ARGS 1 2 3 4 5 6 ? +// ARGS 6 5 4 3 2 1 ? +// ARGS 3 5 2 1 6 4 ? +// ARGS 5 6 3 1 4 2 ? +// ARGS 5 6 3 ? 1 ? 4 ? 2 ? +// ARGS 8 4 9 4 3 1 10 2 5 7 11 6 ? +// ARGS 5 6 3 ? - ? 1 ? 4 ? 2 ? - ? - ? - ? - ? + +#include +#include +#include + +#include "MaxHeap.h" + +// Storing pointers to integers + +// The comparator for integer items + +int comparator(const void* p1, const void* p2) { + int d = *(int*)p1 - *(int*)p2; + return (d > 0) - (d < 0); +} + +// The printer for integer items + +void printer(void* p) { printf("%d ", *(int*)p); } + +int main(int argc, char* argv[]) { + printf("CREATE AN EMPTY HEAP\n"); + // with capacity for at most argc items + MaxHeap* h1 = MaxHeapCreate(argc, comparator, printer); + printf("Capacity = %d\n", MaxHeapCapacity(h1)); + printf("Size = %d\n", MaxHeapSize(h1)); + + printf("\nPROCESS ARGS\n"); + for (int i = 1; i < argc; i++) { + int* aux; + char* arg = argv[i]; + printf("ARG %s: ", arg); + switch (arg[0]) { + case '?': // View and Check + printf("View\n"); + MaxHeapView(h1); // for debugging + printf("Check: %s\n", MaxHeapCheck(h1) ? "OK" : "ERROR"); + break; + case '-': + aux = (int*)MaxHeapGetMax(h1); + printf("Removing %d\n", *aux); + MaxHeapRemoveMax(h1); + free(aux); + break; + default: // assume it's an item to insert + aux = (int*)malloc(sizeof(*aux)); + *aux = atoi(arg); + printf("Inserting %d\n", *aux); + MaxHeapInsert(h1, aux); + } + } + printf("\nFINISHED ARGS\n"); + + printf("Size = %d\n", MaxHeapSize(h1)); + + printf("\nREMOVING REMAINING ITEMS\n"); + while (!MaxHeapIsEmpty(h1)) { + int* aux = (int*)MaxHeapGetMax(h1); + printf("Removing %d\n", *aux); + MaxHeapRemoveMax(h1); + free(aux); + } + printf("\nFINISHED REMOVING\n"); + MaxHeapView(h1); + + MaxHeapDestroy(&h1); + + return 0; +} diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Date.c b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Date.c new file mode 100644 index 0000000..41d7560 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Date.c @@ -0,0 +1,176 @@ + +// JMR, 2021 + +// Complete the functions (marked by ...) +// so that it passes all tests in DateTest. + +#include "Date.h" + +#include +#include +#include + +const Date DateMIN = {0, 1, 1}; +const Date DateMAX = {9999, 12, 31}; + +// Check if a yy,mm,dd tuple forms a valid date. +// (This would be a public static method in Java.) +int DateIsValid(int yy, int mm, int dd) { + return (DateMIN.year) <= yy && yy <= (DateMAX.year) && 1 <= mm && mm <= 12 && + 1 <= dd && dd <= DateDaysInMonth(yy, mm); +} + +// Function to test desired internal invariant for valid Date values: +// the Date should contain valid year,month,day fields. +static int invariant(Date* d) { return DateIsValid(d->year, d->month, d->day); } + +// Alocate and store a date given by yy, mm, dd integers. +// (yy, mm, dd) are required to form a valid date. +// Returns the pointer to the new date structure, +// or NULL if allocation fails. +Date* DateCreate(int yy, int mm, int dd) { + assert(DateIsValid(yy, mm, dd)); + + // JMADEIRA + Date* d = malloc(sizeof(*d)); + if (d == NULL) { + return NULL; + } + + d->year = (uint16_t)yy; + d->month = (uint8_t)mm; + d->day = (uint8_t)dd; + + assert(invariant(d)); // check invariant + return d; +} + +// Free the memory pointed to by *pd and invalidate *pd contents. +// Precondition: *pd must not be NULL. +// Postcondition: *pd is set to NULL. +void DateDestroy(Date** pd) { + assert(*pd != NULL); + + // JMADEIRA + free(*pd); + *pd = NULL; +} + +// table of month lengths in common and leap years +static const uint8_t monthLength[][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + +int DateDaysInMonth(int yy, int mm) { + int isLeap = DateIsLeapYear(yy); + return monthLength[isLeap][mm - 1]; +} + +int DateIsLeapYear(int yy) { + return (yy % 4 == 0 && yy % 100 != 0) || yy % 400 == 0; +} + +static char* fmts[] = { + (char*)"%04d-%02d-%02d", // YMD + (char*)"%3$02d/%2$02d/%1$04d", // DMY + (char*)"%2$02d/%3$02d/%1$04d", // MDY +}; + +static char strBuffer[64]; + +// Return a formatted string representation of date d. +// Careful: the string buffer will be overwritten by the next call. +// You should strcpy or strdup the result if you need persistence! +char* DateFormat(const Date* d, int FMT) { + if (d == NULL) + snprintf(strBuffer, sizeof(strBuffer), "NULL"); + else + snprintf(strBuffer, sizeof(strBuffer), fmts[FMT], d->year, d->month, + d->day); + return strBuffer; +} + +// Parse str according to format and return NEW Date, +// or NULL if invalid or memory error. +Date* DateParse1(const char* str, int FMT) { + int yy, mm, dd; + int n = sscanf(str, fmts[FMT], &yy, &mm, &dd); + Date* d = NULL; + if (n == 3 && DateIsValid(yy, mm, dd)) { + d = DateCreate(yy, mm, dd); + } + return d; +} + +// Parse str according to format and fill in *d. +// Return 1 and update *d if str contains a correctly formatted and valid date. +// Return 0 and leave *d untouched, otherwise. +int DateParse(Date* d, const char* str, int FMT) { + int yy, mm, dd; + int n = sscanf(str, fmts[FMT], &yy, &mm, &dd); + if (!(n == 3 && DateIsValid(yy, mm, dd))) return 0; + d->year = yy; + d->month = mm; + d->day = dd; + return 1; +} + +// Compare dates a and b. +// Return an integer >0 if a>b, 0 if a==b and <0 if ayear - (int)b->year; + if (r != 0) { + return r; + } + r = (int)a->month - (int)b->month; + if (r != 0) { + return r; + } + r = (int)a->day - (int)b->day; + return r; +} + +// Increment date. +// Precondition: d must precede DateMAX. +void DateIncr(Date* d) { + assert(DateCompare(d, &DateMAX) < 0); + + // JMADEIRA + if ((int)d->day < DateDaysInMonth((int)(d->year), (int)(d->month))) { + d->day++; + } else { + d->day = 1; + if ((int)d->month < 12) { + d->month++; + } else { + d->month = (uint8_t)1; + d->year++; + } + } + + assert(invariant(d)); // check invariant +} + +// Decrement date. +// Precondition: d must succeed DateMIN. +void DateDecr(Date* d) { + assert(DateCompare(d, &DateMIN) > 0); + + // JMADEIRA + if ((int)d->day > 1) { + d->day--; + } else { + // decrMonth + if ((int)d->month > 1) { + d->month--; + } else { + d->year--; + d->month = (uint8_t)12; + } + d->day = DateDaysInMonth((int)(d->year), (int)(d->month)); + } + + assert(invariant(d)); // check invariant +} diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Date.h b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Date.h new file mode 100644 index 0000000..3acfa49 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Date.h @@ -0,0 +1,49 @@ + +// JMR, 2021 + +#ifndef _DATE_ +#define _DATE_ + +#include + +struct _date { + uint16_t year; + uint8_t month; + uint8_t day; +}; + +// The Date type. (To be used in clients.) +typedef struct _date Date; + +// Constants +extern const Date DateMIN; +extern const Date DateMAX; + +// Macros to select date format +#define YMD 0 +#define DMY 1 +#define MDY 2 + +Date* DateCreate(int yy, int mm, int dd); + +void DateDestroy(Date** pd); + +int DateIsValid(int yy, int mm, int dd); + +int DateDaysInMonth(int yy, int mm); + +int DateIsLeapYear(int yy); + +char* DateFormat(const Date* d, int FMT); + +Date* DateParse1(const char* str, int FMT); + +int DateParse(Date* d, const char* str, int FMT); + +int DateCompare(const Date* a, const Date* b); + +void DateIncr(Date* d); + +void DateDecr(Date* d); + +#endif //_DATE_ diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/MaxHeap.c b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/MaxHeap.c new file mode 100644 index 0000000..dc1e6e6 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/MaxHeap.c @@ -0,0 +1,184 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira / Joao Manuel Rodrigues +// +// Binary Max Heap storing pointers to generic items. +// + +#include "MaxHeap.h" + +#include +#include +#include + +// +// A binary or 2-way heap is a complete tree stored in an array. +// +// +-------------------------------------------------------------------------------+ +// | 0 | +// +---------------------------------------+---------------------------------------+ +// | 1 | 2 | +// +-------------------+-------------------+-------------------+-------------------+ +// | 3 | 4 | 5 | 6 | +// +---------+---------+---------+---------+---------+---------+---------+---------+ +// | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 +// | +// +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +// | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | +// 30 | +// +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +// +// The children of node k, if any, are 2*k+1 and 2*k+2. +// +// The value of each node cannot be SMALLER that those of its children. +// + +// The heap data structure +struct _Heap { + void** array; + int capacity; + int size; + compFunc compare; + printFunc print; +}; + +MaxHeap* MaxHeapCreate(int capacity, compFunc compF, printFunc printF) { + MaxHeap* h = (MaxHeap*)malloc(sizeof(MaxHeap)); // alloc heap header + if (h == NULL) abort(); + h->array = (void**)malloc(capacity * sizeof(void*)); // alloc array + if (h->array == NULL) { + free(h); + abort(); + } + h->capacity = capacity; + h->size = 0; + h->compare = compF; + h->print = printF; + return h; +} + +void MaxHeapDestroy(MaxHeap** pph) { + MaxHeap* ph = *pph; + if (ph == NULL) return; + free(ph->array); + free(ph); + *pph = NULL; +} + +int MaxHeapCapacity(const MaxHeap* ph) { return ph->capacity; } + +int MaxHeapSize(const MaxHeap* ph) { return ph->size; } + +int MaxHeapIsEmpty(const MaxHeap* ph) { return ph->size == 0; } + +int MaxHeapIsFull(const MaxHeap* ph) { return ph->size == ph->capacity; } + +void* MaxHeapGetMax(const MaxHeap* ph) { + assert(!MaxHeapIsEmpty(ph)); + return ph->array[0]; +} + +// Internal functions + +// n is the index of a node (n in [0, size[). +// _child(n, 1) is the index of the first child of node n, if < size. +// _child(n, 2) is the index of the second child of node n, if < size. +static inline int _child(int n, int c) { return 2 * n + c; } + +// _parent(n) is the index of the parent node of node n, if n>0. +static inline int _parent(int n) { + assert(n > 0); + return (n - 1) / 2; +} + +// Insert the item into the heap +void MaxHeapInsert(MaxHeap* ph, void* item) { + assert(!MaxHeapIsFull(ph)); + // start at the first vacant spot (just after the last occupied node) + int n = ph->size; + while (n > 0) { + int p = _parent(n); + + // if item not larger than _parent, then we've found the right spot! + if (ph->compare(item, ph->array[p]) <= 0) break; + + // otherwise, move down the item at node p to open up space for new item + ph->array[n] = ph->array[p]; + + // update + n = p; // p is the new vacant spot + } + ph->array[n] = item; // store item at node n + ph->size++; +} + +// Remove the Max item +void MaxHeapRemoveMax(MaxHeap* ph) { + assert(!MaxHeapIsEmpty(ph)); + + ph->size--; // NOTE: we're decreasing the size first! + int n = 0; // the just emptied spot... must fill it with largest child + while (1) { + // index of first child + int max = _child(n, 1); // first child (might not exist) + + if (!(max < ph->size)) break; // if no second child, stop looking + + // if second child is larger, choose it + if (ph->compare(ph->array[max + 1], ph->array[max]) > 0) { + max = max + 1; + } + + // if largest child is not larger than last, stop looking + if (!(ph->compare(ph->array[max], ph->array[ph->size]) > 0)) break; + + // move largest child to fill empty _parent spot + ph->array[n] = ph->array[max]; + + n = max; // now, the largest child spot was just emptied! + } + + // move last element to emptied spot + ph->array[n] = ph->array[ph->size]; + + // mark last element as vacant + ph->array[ph->size] = NULL; +} + +// Check the (max-)heap property (the heap invariant): +// Each node must be >= than each of its children. +// Equivalently (but easier): +// Each node must be <= its parent. +int MaxHeapCheck(const MaxHeap* ph) { + // For each node other than root: compare with its parent + for (int n = 1; n < ph->size; n++) { + int p = _parent(n); + if (ph->compare(ph->array[n], ph->array[p]) > 0) return 0; + } + return 1; +} + +// Visualize the heap items as a tree +static void _HeapView(const MaxHeap* ph, int level, const char* edge, + int root) { + if (root < ph->size) { + _HeapView(ph, level + 1, "/", _child(root, 1)); + printf("%*s", 4 * level, edge); + ph->print(ph->array[root]); + printf("\n"); + _HeapView(ph, level + 1, "\\", _child(root, 2)); + } +} + +// Visualize the heap both as a tree and as an array. +void MaxHeapView(const MaxHeap* ph) { + printf("tree:\n"); + _HeapView(ph, 0, ":", 0); // : marks the root + printf("array:"); + for (int i = 0; i < ph->size; i++) { + printf(" "); + ph->print(ph->array[i]); + } + printf("\nsize: %d\n", ph->size); +} diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/MaxHeap.h b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/MaxHeap.h new file mode 100644 index 0000000..af9d1fe --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/MaxHeap.h @@ -0,0 +1,51 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira / Joao Manuel Rodrigues +// +// Binary Max Heap storing pointers to generic items. +// + +#ifndef _MAX_HEAP_ +#define _MAX_HEAP_ + +// The type for MaxHeap instances +typedef struct _Heap MaxHeap; + +// The type for item comparator functions +typedef int (*compFunc)(const void* p1, const void* p2); + +// The type for item printer functions +typedef void (*printFunc)(void* p); + +// CREATE/DESTROY + +MaxHeap* MaxHeapCreate(int capacity, compFunc compF, printFunc printF); + +void MaxHeapDestroy(MaxHeap** pph); + +// GETTERS + +int MaxHeapCapacity(const MaxHeap* ph); + +int MaxHeapSize(const MaxHeap* ph); + +int MaxHeapIsEmpty(const MaxHeap* ph); + +int MaxHeapIsFull(const MaxHeap* ph); + +void* MaxHeapGetMax(const MaxHeap* ph); + +// MODIFY + +void MaxHeapInsert(MaxHeap* ph, void* item); + +void MaxHeapRemoveMax(MaxHeap* ph); + +// CHECK/VIEW + +int MaxHeapCheck(const MaxHeap* ph); + +void MaxHeapView(const MaxHeap* ph); + +#endif diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Person.c b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Person.c new file mode 100644 index 0000000..b8771c6 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Person.c @@ -0,0 +1,105 @@ + +// JMR, 2021 + +// Complete the functions (marked by ...) +// so that it passes all tests in PersonTest. + +#include "Person.h" + +#include +#include +#include +#include + +// This variable stores the last ID that was assigned to a Person. +// It should be used to assign serial, unique IDs automatically upon creation. +// The first person will have id=1, the second id=2, etc. +static int lastID = 0; + +// Alocate and store a Person. +// Returns the pointer to the new structure, +// or NULL if allocation fails. +// The names are copied to internally allocated memory. +Person *PersonCreate(const char *fname, const char *lname, int yy, int mm, + int dd) { + // JMADEIRA + Person *p = malloc(sizeof(*p)); + if (p == NULL) { + return p; + } + + // Allocating memory for the name strings + size_t flen = strnlen(fname, 100); + size_t llen = strnlen(lname, 100); + + char *s1 = malloc((flen + 1) * sizeof(char)); + if (s1 == NULL) { + free(p); + return NULL; + } + + char *s2 = malloc((llen + 1) * sizeof(char)); + if (s2 == NULL) { + free(s1); + free(p); + return NULL; + } + + p->id = ++lastID; + + // DIRECT ACCESS + p->birthDate.year = (uint16_t)yy; + p->birthDate.month = (uint8_t)mm; + p->birthDate.day = (uint8_t)dd; + + p->firstName = s1; + p->lastName = s2; + strcpy(p->firstName, fname); // copy the names + strcpy(p->lastName, lname); + + return p; +} + +// Free the memory pointed to by *pp and by the names inside it, +// and invalidate *pp contents. +// Precondition: *pp must not be NULL. +// Postcondition: *pp is set to NULL. +void PersonDestroy(Person **pp) { + assert(*pp != NULL); + + // JMADEIRA + free((*pp)->firstName); // free the names + free((*pp)->lastName); + free(*pp); + *pp = NULL; +} + +// Prints a person formatted as "[id, lastname, firstname, birthdate]", +// followed by a suffix string. +void PersonPrintf(Person *p, const char *suffix) { + if (p == NULL) + printf("NULL%s", suffix); + else + printf("(%d, %s, %s, %s)%s", p->id, p->lastName, p->firstName, + DateFormat(&(p->birthDate), YMD), suffix); +} + +// Compare birth dates of two persons. +// Return a negative/positive integer if p1 was born before/after p2. +// Return zero if p1 and p2 were born on the same date. +int PersonCompareByBirth(const Person *p1, const Person *p2) { + // JMADEIRA + return DateCompare(&(p1->birthDate), &(p2->birthDate)); +} + +// Compare two persons by last name, then first name (if last name is the same). +// Return a -/+/0 integer if p1 precedes/succeeds/is equal to p2. +int PersonCompareByLastFirstName(const Person *p1, const Person *p2) { + // JMADEIRA + int cmp = strcmp(p1->lastName, p2->lastName); + if (cmp != 0) { + return cmp; + } + cmp = strcmp(p1->firstName, p2->firstName); + return cmp; +} diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Person.h b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Person.h new file mode 100644 index 0000000..d9a7a21 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Person.h @@ -0,0 +1,27 @@ + +// JMR, 2021 + +#ifndef _PERSON_ +#define _PERSON_ + +#include "Date.h" + +typedef struct { + int id; + Date birthDate; // this is the actual structure, not a pointer! + char *firstName; + char *lastName; +} Person; + +Person *PersonCreate(const char *fname, const char *lname, int yy, int mm, + int dd); + +void PersonDestroy(Person **pd); + +void PersonPrintf(Person *p, const char *suffix); + +int PersonCompareByBirth(const Person *p1, const Person *p2); + +int PersonCompareByLastFirstName(const Person *p1, const Person *p2); + +#endif // PERSON diff --git a/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Tests.c b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Tests.c new file mode 100644 index 0000000..d991fac --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema08/18_AED_Arvores_Binarias_IV/02_Example_MAX_HEAP/Tests.c @@ -0,0 +1,86 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira / Joao Manuel Rodrigues +// +// Creating Max Heaps of persons, with different comparator functions. +// + +#include +#include +#include + +#include "MaxHeap.h" +#include "Person.h" + +// Comparators for Persons + +int ComparatorByBirthday(const void* p1, const void* p2) { + return PersonCompareByBirth((Person*)p1, (Person*)p2); +} + +int ComparatorByLastFirstName(const void* p1, const void* p2) { + return PersonCompareByLastFirstName((Person*)p1, (Person*)p2); +} + +// The printer for Persons + +void Printer(void* p) { PersonPrintf((Person*)p, " "); } + +int main(void) { + // An array of persons + const int NP = 10; // number of persons + Person* person[NP]; + person[0] = PersonCreate("Eva", "Maia", 1977, 10, 20); + person[1] = PersonCreate("Maria", "Silva", 2003, 12, 30); + person[2] = PersonCreate("Paulo", "Guedes", 2003, 12, 31); + person[3] = PersonCreate("Carlos", "Silva", 1999, 8, 31); + person[4] = PersonCreate("Filipe", "Matos", 2001, 1, 1); + person[5] = PersonCreate("Carla", "Oliveira", 1959, 1, 1); + person[6] = PersonCreate("Vitor", "Maia", 1969, 2, 28); + person[7] = PersonCreate("Olga", "Costa", 1967, 2, 29); + person[8] = PersonCreate("Tiago", "Santos", 1996, 6, 13); + person[9] = PersonCreate("Sara", "Santos", 2007, 3, 1); + + printf("\n--- Create a Max Heap, ordered according to person bithday ---\n"); + MaxHeap* heap_1 = MaxHeapCreate(NP, ComparatorByBirthday, Printer); + + printf("\n--- Create a Max Heap, ordered according to person name ---\n"); + MaxHeap* heap_2 = MaxHeapCreate(NP, ComparatorByLastFirstName, Printer); + + printf("\n--- Adding persons to the heaps ---\n"); + for (size_t n = 0; n < 6; n++) { + int i = rand() % NP; + MaxHeapInsert(heap_1, person[i]); + MaxHeapInsert(heap_2, person[i]); + } + + printf("\n--- Printing the heaps ---\n"); + MaxHeapView(heap_1); + MaxHeapView(heap_2); + + printf("\n--- Listing heap contents in non-increasing birthday order ---\n"); + while (!MaxHeapIsEmpty(heap_1)) { + Person* p = MaxHeapGetMax(heap_1); + PersonPrintf(p, "\n"); + MaxHeapRemoveMax(heap_1); + } + + printf("\n--- Listing heap contents in non-increasing name order ---\n"); + while (!MaxHeapIsEmpty(heap_2)) { + Person* p = MaxHeapGetMax(heap_2); + PersonPrintf(p, "\n"); + MaxHeapRemoveMax(heap_2); + } + + // Free everything + // (If you comment out any of these, valgrind should detect it!) + for (int i = 0; i < NP; i++) { + PersonDestroy(&(person[i])); + } + + MaxHeapDestroy(&heap_1); + MaxHeapDestroy(&heap_2); + + return 0; +} diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/01_example.c b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/01_example.c new file mode 100644 index 0000000..09c76a0 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/01_example.c @@ -0,0 +1,150 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table using Open Addressing +// Key and Value are STRINGS - To simplify the example +// + +#include +#include + +#include "HashTable.h" + +int main(void) { + // FIRST HT - Use the first key character only - Linear Probing + printf( + "\nHT 1 --- Hashing with first key character only" + "\n --- Linear Probing\n"); + + HashTable* table01 = HashTableCreate(17, hash1, linearProbing, 0); + + HashTablePut(table01, "January", "1st month of the year"); + HashTablePut(table01, "February", "2nd month of the year"); + HashTablePut(table01, "March", "3rd month"); + HashTablePut(table01, "April", "4th month"); + HashTablePut(table01, "May", "5th month"); + HashTablePut(table01, "June", "6th month"); + HashTablePut(table01, "July", "7th month"); + HashTablePut(table01, "August", "8th month"); + HashTablePut(table01, "September", "9th month"); + HashTablePut(table01, "October", "10th month"); + HashTablePut(table01, "November", "11th month"); + HashTablePut(table01, "December", "12th month"); + HashTableDisplay(table01); + + printf("\nReplacing some table elements\n"); + + HashTableReplace(table01, "December", "The last month of the year"); + HashTableReplace(table01, "February", "The second month of the year"); + HashTableReplace(table01, "November", "Almost at the end of the year"); + HashTableDisplay(table01); + + char* string = HashTableGet(table01, "December"); + printf("\n*** %s = %s ***\n\n", "December", string); + free(string); + + // SECOND HT - Use the first key character only - Quadratic Probing + printf( + "\nHT 2 --- Hashing with first key character only" + "\n --- Quadratic Probing\n"); + + HashTable* table02 = HashTableCreate(17, hash1, quadraticProbing, 0); + + HashTablePut(table02, "January", "1st month of the year"); + HashTablePut(table02, "February", "2nd month of the year"); + HashTablePut(table02, "March", "3rd month"); + HashTablePut(table02, "April", "4th month"); + HashTablePut(table02, "May", "5th month"); + HashTablePut(table02, "June", "6th month"); + HashTablePut(table02, "July", "7th month"); + HashTablePut(table02, "August", "8th month"); + HashTablePut(table02, "September", "9th month"); + HashTablePut(table02, "October", "10th month"); + HashTablePut(table02, "November", "11th month"); + HashTablePut(table02, "December", "12th month"); + HashTableDisplay(table02); + + printf("\nReplacing some table elements\n"); + + HashTableReplace(table02, "December", "The last month of the year"); + HashTableReplace(table02, "February", "The second month of the year"); + HashTableReplace(table02, "November", "Almost at the end of the year"); + HashTableDisplay(table02); + + string = HashTableGet(table02, "December"); + printf("\n*** %s = %s ***\n\n", "December", string); + free(string); + + // THIRD HT - Use the first and second key characters - Linear Probing + printf( + "\nHT 3 --- Hashing with first and second key characters" + "\n --- Linear Probing" + "\n --- Resizing allowed\n"); + + HashTable* table03 = HashTableCreate(17, hash2, linearProbing, 1); + + HashTablePut(table03, "January", "1st month of the year"); + HashTablePut(table03, "February", "2nd month of the year"); + HashTablePut(table03, "March", "3rd month"); + HashTablePut(table03, "April", "4th month"); + HashTablePut(table03, "May", "5th month"); + HashTablePut(table03, "June", "6th month"); + HashTablePut(table03, "July", "7th month"); + HashTablePut(table03, "August", "8th month"); + HashTablePut(table03, "September", "9th month"); + HashTablePut(table03, "October", "10th month"); + HashTablePut(table03, "November", "11th month"); + HashTablePut(table03, "December", "12th month"); + HashTableDisplay(table03); + + HashTableRemove(table03, "January"); + HashTableRemove(table03, "February"); + HashTableRemove(table03, "March"); + HashTableRemove(table03, "April"); + HashTableDisplay(table03); + + HashTableRemove(table03, "May"); + HashTableRemove(table03, "June"); + HashTableRemove(table03, "July"); + HashTableRemove(table03, "August"); + HashTableDisplay(table03); + + HashTableRemove(table03, "September"); + HashTableRemove(table03, "October"); + HashTableRemove(table03, "November"); + HashTableRemove(table03, "December"); + HashTableDisplay(table03); + + // 4TH HT - Use the first and second key characters - Quadratic Probing + printf( + "\nHT 4 --- Hashing with first and second key characters" + "\n --- Quadratic Probing" + "\n --- Resizing allowed\n"); + + HashTable* table04 = HashTableCreate(17, hash2, quadraticProbing, 1); + + HashTablePut(table04, "January", "1st month of the year"); + HashTablePut(table04, "February", "2nd month of the year"); + HashTablePut(table04, "March", "3rd month"); + HashTablePut(table04, "April", "4th month"); + HashTablePut(table04, "May", "5th month"); + HashTablePut(table04, "June", "6th month"); + HashTablePut(table04, "July", "7th month"); + HashTablePut(table04, "August", "8th month"); + HashTablePut(table04, "September", "9th month"); + HashTablePut(table04, "October", "10th month"); + HashTablePut(table04, "November", "11th month"); + HashTablePut(table04, "December", "12th month"); + HashTableDisplay(table04); + + // DESTROYING + + HashTableDestroy(&table01); + HashTableDestroy(&table02); + HashTableDestroy(&table03); + HashTableDestroy(&table04); + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/HashTable.c b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/HashTable.c new file mode 100644 index 0000000..0085e6a --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/HashTable.c @@ -0,0 +1,342 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table using Open Addressing +// Key and Value are STRINGS - To simplify the example +// + +#include "HashTable.h" + +#include +#include +#include +#include + +struct _HashTableBin { + char* key; + char* value; + int isDeleted; + int isFree; +}; + +struct _HashTableHeader { + unsigned int size; + unsigned int numActive; + unsigned int numUsed; + hashFunction hashF; + probeFunction probeF; + int resizeIsEnabled; + struct _HashTableBin* table; +}; + +// Auxiliary functions for experimenting + +unsigned int hash1(const char* key) { + assert(strlen(key) > 0); + return key[0]; +} + +unsigned int hash2(const char* key) { + assert(strlen(key) > 0); + if (strlen(key) == 1) return key[0]; + return key[0] + key[1]; +} + +unsigned int linearProbing(unsigned int index, unsigned int i, + unsigned int size) { + return (index + i) % size; +} + +// +// Simple quadratic probing --- improve !! +// +unsigned int quadraticProbing(unsigned int index, unsigned int i, + unsigned int size) { + return (index + i * i) % size; +} + +// TAD Functions + +HashTable* HashTableCreate(unsigned int size, hashFunction hashF, + probeFunction probeF, int resizeIsEnabled) { + assert(size > 0); + HashTable* hTable = (HashTable*)malloc(sizeof(struct _HashTableHeader)); + assert(hTable != NULL); + hTable->table = + (struct _HashTableBin*)malloc(size * sizeof(struct _HashTableBin)); + assert(hTable->table != NULL); + + hTable->size = size; + hTable->numActive = 0; + hTable->numUsed = 0; + hTable->hashF = hashF; + hTable->probeF = probeF; + hTable->resizeIsEnabled = resizeIsEnabled; + + for (unsigned int i = 0; i < size; i++) { + hTable->table[i].key = NULL; + hTable->table[i].value = NULL; + hTable->table[i].isFree = 1; + hTable->table[i].isDeleted = 0; + } + + return hTable; +} + +void HashTableDestroy(HashTable** p) { + assert(*p != NULL); + HashTable* t = *p; + + for (unsigned int i = 0; i < t->size; i++) { + if (t->table[i].key) free(t->table[i].key); + if (t->table[i].value) free(t->table[i].value); + } + + free(t->table); + free(t); + *p = NULL; +} + +static void _resizeHashTable(HashTable* hashT, unsigned int newSize) { + if (newSize == 0) return; + + // Do this is a better way: choose a near prime + if (newSize % 2 == 0) { + newSize++; + } + + struct _HashTableBin* oldBinsArray = hashT->table; + unsigned int oldSize = hashT->size; + + hashT->table = + (struct _HashTableBin*)malloc(newSize * sizeof(struct _HashTableBin)); + assert(hashT->table != NULL); + + for (unsigned int i = 0; i < newSize; i++) { + hashT->table[i].key = NULL; + hashT->table[i].value = NULL; + hashT->table[i].isFree = 1; + hashT->table[i].isDeleted = 0; + } + + hashT->size = newSize; + hashT->numActive = 0; + hashT->numUsed = 0; + + // Copy items to the new array of bins + // Disable resizing while copying + + hashT->resizeIsEnabled = 0; + + for (unsigned int i = 0; i < oldSize; i++) { + if (oldBinsArray[i].isFree || oldBinsArray[i].isDeleted) { + continue; + } + HashTablePut(hashT, oldBinsArray[i].key, oldBinsArray[i].value); + } + + hashT->resizeIsEnabled = 1; + + // Free the old array + + for (unsigned int i = 0; i < oldSize; i++) { + if (oldBinsArray[i].key) free(oldBinsArray[i].key); + if (oldBinsArray[i].value) free(oldBinsArray[i].value); + } + free(oldBinsArray); +} + +// HashTable properties + +int HashTableIsEmpty(const HashTable* hashT) { return hashT->numActive == 0; } + +int HashTableIsFull(const HashTable* hashT) { + return hashT->numUsed == hashT->size; +} + +// Getters + +int HashTableGetNumberOfItems(const HashTable* hashT) { + return hashT->numActive; +} + +double HashTableGetLoadFactor(const HashTable* hashT) { + return (double)hashT->numActive / (double)hashT->size; +} + +// Operations with items + +// +// If the key belongs to the table, return the corresponding index +// If not, return one (next) available index or -1, if the table is full +// +static int _searchHashTable(const HashTable* hashT, const char* key) { + unsigned int hashKey = hashT->hashF(key); + + unsigned int index; + struct _HashTableBin* bin; + + for (unsigned int i = 0; i < hashT->size; i++) { + index = hashT->probeF(hashKey, i, hashT->size); + + bin = &(hashT->table[index]); + + if (bin->isFree) { + // Not in the table ! + return index; + } + + if ((bin->isDeleted == 0) && (strcmp(bin->key, key) == 0)) { + // Found it ! + return index; + } + } + + // SHOULD NEVER HAPPEN !! + return -1; +} + +int HashTableContains(const HashTable* hashT, const char* key) { + int result = _searchHashTable(hashT, key); + if (result == -1 || hashT->table[result].isFree == 1) { + // NOT FOUND + return 0; + } + return 1; +} + +char* HashTableGet(const HashTable* hashT, const char* key) { + int index = _searchHashTable(hashT, key); + if (index == -1 || hashT->table[index].isFree == 1) { + // NOT FOUND + return NULL; + } + + struct _HashTableBin* bin = &(hashT->table[index]); + char* result = (char*)malloc(sizeof(char) * (1 + strlen(bin->value))); + strcpy(result, bin->value); + + return result; +} + +int HashTablePut(HashTable* hashT, const char* key, const char* value) { + int result = _searchHashTable(hashT, key); + + if (result == -1) { + // NO PLACE AVAILABLE + return 0; + } + + if (hashT->table[result].isFree == 0) { + // ALREADY IN THE TABLE + return 0; + } + + // Does NOT BELONG to the table + // See if it can be stored earlier in the chain, by starting again + // Losing some efficiency here + + unsigned int hashKey = hashT->hashF(key); + + unsigned int index; + struct _HashTableBin* bin; + + for (unsigned int i = 0; i < hashT->size; i++) { + index = hashT->probeF(hashKey, i, hashT->size); + + bin = &(hashT->table[index]); + + if (bin->isFree) { + bin->key = (char*)malloc(sizeof(char) * (1 + strlen(key))); + strcpy(bin->key, key); + bin->value = (char*)malloc(sizeof(char) * (1 + strlen(value))); + strcpy(bin->value, value); + bin->isFree = bin->isDeleted = 0; + + hashT->numActive++; + hashT->numUsed++; + + if (hashT->resizeIsEnabled && HashTableGetLoadFactor(hashT) > 0.5) { + _resizeHashTable(hashT, hashT->size * 2); + } + + return 1; + } + + if (bin->isDeleted) { + bin->key = (char*)malloc(sizeof(char) * (1 + strlen(key))); + strcpy(bin->key, key); + bin->value = (char*)malloc(sizeof(char) * (1 + strlen(value))); + strcpy(bin->value, value); + bin->isFree = bin->isDeleted = 0; + + hashT->numActive++; + + return 1; + } + } + + return 0; +} + +int HashTableReplace(const HashTable* hashT, const char* key, + const char* value) { + int index = _searchHashTable(hashT, key); + if (index == -1 || hashT->table[index].isFree == 1) { + // NOT FOUND + return 0; + } + + struct _HashTableBin* bin = &(hashT->table[index]); + free(bin->value); + bin->value = (char*)malloc(sizeof(char) * (1 + strlen(value))); + strcpy(bin->value, value); + + return 1; +} + +int HashTableRemove(HashTable* hashT, const char* key) { + int index = _searchHashTable(hashT, key); + if (index == -1 || hashT->table[index].isFree == 1) { + // NOT FOUND + return 0; + } + + // Mark as deleted to keep the chain + + hashT->table[index].isDeleted = 1; + hashT->numActive--; + + free(hashT->table[index].key); + free(hashT->table[index].value); + hashT->table[index].key = hashT->table[index].value = NULL; + + if (hashT->resizeIsEnabled && HashTableGetLoadFactor(hashT) < 0.125) { + _resizeHashTable(hashT, hashT->size / 2); + } + + return 1; +} + +// DISPLAYING on the console + +void HashTableDisplay(const HashTable* hashT) { + printf("---\n"); + printf("size = %2d | Used = %2d | Active = %2d\n", hashT->size, + hashT->numUsed, hashT->numActive); + for (unsigned int i = 0; i < hashT->size; i++) { + printf("%3d - ", i); + printf("Free = %d - ", hashT->table[i].isFree); + printf("Deleted = %d - ", hashT->table[i].isDeleted); + if (hashT->table[i].key) { + unsigned int hashValue = hashT->hashF(hashT->table[i].key); + unsigned int firstIndex = hashValue % hashT->size; + printf("Hash = %4d, 1st index = %3d, (%s, %s)\n", hashValue, firstIndex, + hashT->table[i].key, hashT->table[i].value); + } else + printf("\n"); + } + printf("---\n"); +} diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/HashTable.h b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/HashTable.h new file mode 100644 index 0000000..0934669 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/01_Open_Addressing/HashTable.h @@ -0,0 +1,66 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table using Open Addressing +// Key and Value are STRINGS - To simplify the example +// + +#ifndef _HASH_TABLE_ +#define _HASH_TABLE_ + +typedef struct _HashTableHeader HashTable; + +typedef unsigned int (*hashFunction)(const char* key); + +typedef unsigned int (*probeFunction)(unsigned int index, unsigned int i, + unsigned int size); + +// Auxiliary functions for experimenting + +unsigned int hash1(const char* key); +unsigned int hash2(const char* key); + +unsigned int linearProbing(unsigned int index, unsigned int i, + unsigned int size); +unsigned int quadraticProbing(unsigned int index, unsigned int i, + unsigned int size); + +// TAD Functions + +HashTable* HashTableCreate(unsigned int capacity, hashFunction hashF, + probeFunction probeF, int resizeIsEnabled); + +void HashTableDestroy(HashTable** p); + +// HashTable properties + +int HashTableIsEmpty(const HashTable* hashT); + +int HashTableIsFull(const HashTable* hashT); + +// Getters + +int HashTableGetNumberOfItems(const HashTable* hashT); + +double HashTableGetLoadFactor(const HashTable* hashT); + +// Operations with items + +int HashTableContains(const HashTable* hashT, const char* key); + +char* HashTableGet(const HashTable* hashT, const char* key); + +int HashTablePut(HashTable* hashT, const char* key, const char* value); + +int HashTableReplace(const HashTable* hashT, const char* key, + const char* value); + +int HashTableRemove(HashTable* hashT, const char* key); + +// DISPLAYING on the console + +void HashTableDisplay(const HashTable* hashT); + +#endif // _HASH_TABLE_ diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/.gitignore b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/.gitignore new file mode 100644 index 0000000..2211df6 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/02_example.c b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/02_example.c new file mode 100644 index 0000000..ec86d22 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/02_example.c @@ -0,0 +1,77 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple exmaple for COUNTING WORDS using Open Addressing +// Keys are STRINGS - Values are INTEGERS +// Adapted from TOS - AED - 2015 +// + +#include +#include + +#include "HashTable.h" + +void registerWords(HashTable* hashT, FILE* file) { + // + // scan the entire file + // + // token processing SHOULD BE improved !!!!! + // + + char line[10000]; + char word[64]; + int i; + int j; + + while (fgets(line, sizeof(line), file) != NULL) { + // replace non-digits and non-letters by a space + for (i = 0; line[i] != '\0'; i++) + if ((line[i] < '0' || line[i] > '9') && + (line[i] < 'A' || line[i] > 'Z') && + (line[i] < 'a' || line[i] > 'z') && line[i] != '\'') + line[i] = ' '; + // go over the line and extract each word + for (i = 0; line[i] != '\0'; i += j) + if (line[i] == ' ') + j = 1; + else { + for (j = 0; line[i + j] != '\0' && line[i + j] != ' '; j++) + if (j < 63) word[j] = line[i + j]; + word[(j < 63) ? j : 63] = '\0'; + + HashTableIncrement(hashT, word); + } + } +} + +int main(int argc, char** argv) { + if (argc == 1) { + printf("program_name file_name\n"); + return 0; + } + + FILE* file = fopen(argv[1], "r"); + if (file == NULL) { + fprintf(stderr, "Unable to open file %s\n", argv[1]); + exit(1); + } + + // HT - Use the first two key characters only - Linear Probing - Resizing + + HashTable* countsTable = HashTableCreate(50021, hash2, linearProbing, 1); + + registerWords(countsTable, file); + + HashTableDisplayItems(countsTable); + + // Closing the file + fclose(file); + + // DESTROYING + + HashTableDestroy(&countsTable); + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/HashTable.c b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/HashTable.c new file mode 100644 index 0000000..858dc96 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/HashTable.c @@ -0,0 +1,363 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table for COUNTING WORDS using Open Addressing +// Keys are STRINGS - Values are INTEGERS +// + +#include "HashTable.h" + +#include +#include +#include +#include + +struct _HashTableBin { + char* key; + unsigned int value; + int isDeleted; + int isFree; +}; + +struct _HashTableHeader { + unsigned int size; + unsigned int numActive; + unsigned int numUsed; + hashFunction hashF; + probeFunction probeF; + int resizeIsEnabled; + struct _HashTableBin* table; +}; + +// Auxiliary functions for experimenting + +unsigned int hash1(const char* key) { + assert(strlen(key) > 0); + return key[0]; +} + +unsigned int hash2(const char* key) { + assert(strlen(key) > 0); + if (strlen(key) == 1) return key[0]; + return key[0] + key[1]; +} + +unsigned int linearProbing(unsigned int index, unsigned int i, + unsigned int size) { + return (index + i) % size; +} + +// +// Simple quadratic probing --- improve !! +// +unsigned int quadraticProbing(unsigned int index, unsigned int i, + unsigned int size) { + return (index + i * i) % size; +} + +// TAD Functions + +HashTable* HashTableCreate(unsigned int size, hashFunction hashF, + probeFunction probeF, int resizeIsEnabled) { + assert(size > 0); + HashTable* hTable = (HashTable*)malloc(sizeof(struct _HashTableHeader)); + assert(hTable != NULL); + hTable->table = + (struct _HashTableBin*)malloc(size * sizeof(struct _HashTableBin)); + assert(hTable->table != NULL); + + hTable->size = size; + hTable->numActive = 0; + hTable->numUsed = 0; + hTable->hashF = hashF; + hTable->probeF = probeF; + hTable->resizeIsEnabled = resizeIsEnabled; + + for (unsigned int i = 0; i < size; i++) { + hTable->table[i].key = NULL; + hTable->table[i].value = 0; + hTable->table[i].isFree = 1; + hTable->table[i].isDeleted = 0; + } + + return hTable; +} + +void HashTableDestroy(HashTable** p) { + assert(*p != NULL); + HashTable* t = *p; + + for (unsigned int i = 0; i < t->size; i++) { + if (t->table[i].key) free(t->table[i].key); + } + free(t->table); + free(t); + *p = NULL; +} + +static void _resizeHashTable(HashTable* hashT, unsigned int newSize) { + if (newSize == 0) return; + + // Do this is a better way: choose a near prime + if (newSize % 2 == 0) { + newSize++; + } + + struct _HashTableBin* oldBinsArray = hashT->table; + unsigned int oldSize = hashT->size; + + hashT->table = + (struct _HashTableBin*)malloc(newSize * sizeof(struct _HashTableBin)); + assert(hashT->table != NULL); + + for (unsigned int i = 0; i < newSize; i++) { + hashT->table[i].key = NULL; + hashT->table[i].value = 0; + hashT->table[i].isFree = 1; + hashT->table[i].isDeleted = 0; + } + + hashT->size = newSize; + hashT->numActive = 0; + hashT->numUsed = 0; + + // Copy items to the new array of bins + // Disable resizing while copying + + hashT->resizeIsEnabled = 0; + + for (unsigned int i = 0; i < oldSize; i++) { + if (oldBinsArray[i].isFree || oldBinsArray[i].isDeleted) { + continue; + } + HashTablePut(hashT, oldBinsArray[i].key, oldBinsArray[i].value); + } + + hashT->resizeIsEnabled = 1; + + // Free the old array + + for (unsigned int i = 0; i < oldSize; i++) { + if (oldBinsArray[i].key) free(oldBinsArray[i].key); + } + free(oldBinsArray); +} + +// HashTable properties + +int HashTableIsEmpty(const HashTable* hashT) { return hashT->numActive == 0; } + +int HashTableIsFull(const HashTable* hashT) { + return hashT->numUsed == hashT->size; +} + +// Getters + +int HashTableGetNumberOfItems(const HashTable* hashT) { + return hashT->numActive; +} + +double HashTableGetLoadFactor(const HashTable* hashT) { + return (double)hashT->numActive / (double)hashT->size; +} + +// Operations with items + +// +// If the key belongs to the table, return the corresponding index +// If not, return one (next) available index or -1, if the table is full +// +static int _searchHashTable(const HashTable* hashT, const char* key) { + unsigned int hashKey = hashT->hashF(key); + + unsigned int index; + struct _HashTableBin* bin; + + for (unsigned int i = 0; i < hashT->size; i++) { + index = hashT->probeF(hashKey, i, hashT->size); + + bin = &(hashT->table[index]); + + if (bin->isFree) { + // Not in the table ! + return index; + } + + if ((bin->isDeleted == 0) && (strcmp(bin->key, key) == 0)) { + // Found it ! + return index; + } + } + + // SHOULD NEVER HAPPEN !! + return -1; +} + +int HashTableContains(const HashTable* hashT, const char* key) { + int result = _searchHashTable(hashT, key); + if (result == -1 || hashT->table[result].isFree == 1) { + // NOT FOUND + return 0; + } + return 1; +} + +unsigned int HashTableGet(const HashTable* hashT, const char* key) { + int index = _searchHashTable(hashT, key); + if (index == -1 || hashT->table[index].isFree == 1) { + // NOT FOUND + return 0; + } + + return hashT->table[index].value; +} + +int HashTablePut(HashTable* hashT, const char* key, unsigned int value) { + int result = _searchHashTable(hashT, key); + + if (result == -1) { + // NO PLACE AVAILABLE + return 0; + } + + if (hashT->table[result].isFree == 0) { + // ALREADY IN THE TABLE + return 0; + } + + // Does NOT BELONG to the table + // See if it can be stored earlier in the chain, by starting again + // Losing some efficiency here + + unsigned int hashKey = hashT->hashF(key); + + unsigned int index; + struct _HashTableBin* bin; + + for (unsigned int i = 0; i < hashT->size; i++) { + index = hashT->probeF(hashKey, i, hashT->size); + + bin = &(hashT->table[index]); + + if (bin->isFree) { + bin->key = (char*)malloc(sizeof(char) * (1 + strlen(key))); + strcpy(bin->key, key); + bin->value = value; + bin->isFree = bin->isDeleted = 0; + + hashT->numActive++; + hashT->numUsed++; + + if (hashT->resizeIsEnabled && HashTableGetLoadFactor(hashT) > 0.5) { + _resizeHashTable(hashT, hashT->size * 2); + } + + return 1; + } + + if (bin->isDeleted) { + bin->key = (char*)malloc(sizeof(char) * (1 + strlen(key))); + strcpy(bin->key, key); + bin->value = value; + bin->isFree = bin->isDeleted = 0; + + hashT->numActive++; + + return 1; + } + } + + return 0; +} + +// +// Increment the current value +// If key does not exist, insert it with a count of 1 +// +int HashTableIncrement(HashTable* hashT, const char* key) { + int index = _searchHashTable(hashT, key); + if (index == -1) { + // NOT FOUND AND NO PLACE --- SHOULD NOT HAPPEN !! + return 0; + } + + if (hashT->table[index].isFree == 0) { + // ALREADY IN THE TABLE - INCREMENT + + hashT->table[index].value++; + return 1; + } + + // NEW KEY - INSERT + // LOOSING SOME EFFICIENCY HERE + + return HashTablePut(hashT, key, 1); +} + +int HashTableReplace(const HashTable* hashT, const char* key, + unsigned int value) { + int index = _searchHashTable(hashT, key); + if (index == -1 || hashT->table[index].isFree == 1) { + // NOT FOUND + return 0; + } + + hashT->table[index].value = value; + + return 1; +} + +int HashTableRemove(HashTable* hashT, const char* key) { + int index = _searchHashTable(hashT, key); + if (index == -1 || hashT->table[index].isFree == 1) { + // NOT FOUND + return 0; + } + + // Mark as deleted to keep the chain + + hashT->table[index].isDeleted = 1; + hashT->numActive--; + + free(hashT->table[index].key); + hashT->table[index].key = NULL; + hashT->table[index].value = 0; + + if (hashT->resizeIsEnabled && HashTableGetLoadFactor(hashT) < 0.125) { + _resizeHashTable(hashT, hashT->size / 2); + } + + return 1; +} + +// DISPLAYING on the console + +void HashTableDisplay(const HashTable* hashT) { + printf("---\n"); + printf("size = %2d | Used = %2d | Active = %2d\n", hashT->size, + hashT->numUsed, hashT->numActive); + for (unsigned int i = 0; i < hashT->size; i++) { + printf("%3d - ", i); + printf("Free = %d - ", hashT->table[i].isFree); + printf("Deleted = %d - ", hashT->table[i].isDeleted); + if (hashT->table[i].key) { + unsigned int hashValue = hashT->hashF(hashT->table[i].key); + unsigned int firstIndex = hashValue % hashT->size; + printf("Hash = %4d, 1st index = %3d, (%s, %d)\n", hashValue, firstIndex, + hashT->table[i].key, hashT->table[i].value); + } else + printf("\n"); + } + printf("---\n"); +} + +void HashTableDisplayItems(const HashTable* hashT) { + printf("NUMBER OF ITEMS = %d\n\n", hashT->numActive); + for (unsigned int i = 0; i < hashT->size; i++) { + if (hashT->table[i].key) { + printf("%s %d\n", hashT->table[i].key, hashT->table[i].value); + } + } +} diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/HashTable.h b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/HashTable.h new file mode 100644 index 0000000..3ea80d7 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/02_Counting_Words/HashTable.h @@ -0,0 +1,70 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table for COUNTING WORDS using Open Addressing +// Keys are STRINGS - Values are INTEGERS +// + +#ifndef _HASH_TABLE_ +#define _HASH_TABLE_ + +typedef struct _HashTableHeader HashTable; + +typedef unsigned int (*hashFunction)(const char* key); + +typedef unsigned int (*probeFunction)(unsigned int index, unsigned int i, + unsigned int size); + +// Auxiliary functions for experimenting + +unsigned int hash1(const char* key); +unsigned int hash2(const char* key); + +unsigned int linearProbing(unsigned int index, unsigned int i, + unsigned int size); +unsigned int quadraticProbing(unsigned int index, unsigned int i, + unsigned int size); + +// TAD Functions + +HashTable* HashTableCreate(unsigned int capacity, hashFunction hashF, + probeFunction probeF, int resizeIsEnabled); + +void HashTableDestroy(HashTable** p); + +// HashTable properties + +int HashTableIsEmpty(const HashTable* hashT); + +int HashTableIsFull(const HashTable* hashT); + +// Getters + +int HashTableGetNumberOfItems(const HashTable* hashT); + +double HashTableGetLoadFactor(const HashTable* hashT); + +// Operations with items + +int HashTableContains(const HashTable* hashT, const char* key); + +unsigned int HashTableGet(const HashTable* hashT, const char* key); + +int HashTablePut(HashTable* hashT, const char* key, unsigned int value); + +int HashTableIncrement(HashTable* hashT, const char* key); + +int HashTableReplace(const HashTable* hashT, const char* key, + unsigned int value); + +int HashTableRemove(HashTable* hashT, const char* key); + +// DISPLAYING on the console + +void HashTableDisplay(const HashTable* hashT); + +void HashTableDisplayItems(const HashTable* hashT); + +#endif // _HASH_TABLE_ diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/README.txt b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/README.txt new file mode 100644 index 0000000..f8169c9 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/19_AED_Dicionarios_I/README.txt @@ -0,0 +1,10 @@ + +Hash Table using Open Addressing + +Partially based on source code from + +*The Joys of Hashing* + +by Thomas Mailund + +https://www.apress.com/9781484240656 \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema09/19_AED__Dicionarios_I.pdf b/2ano/1semestre/aed/teoricas/tema09/19_AED__Dicionarios_I.pdf new file mode 100644 index 0000000..812ebce Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema09/19_AED__Dicionarios_I.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/01_example.c b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/01_example.c new file mode 100644 index 0000000..6e0aeea --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/01_example.c @@ -0,0 +1,85 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table using Separate Chaining +// Key and Value are STRINGS - To simplify the example +// + +#include +#include + +#include "HashTable.h" + +int main(void) { + // FIRST HT - Use the first key character only + + HashTable* table01 = HashTableCreate(17, hash1); + + HashTablePut(table01, "January", "1st month of the year"); + HashTablePut(table01, "February", "2nd month of the year"); + HashTablePut(table01, "March", "3rd month"); + HashTablePut(table01, "April", "4th month"); + HashTablePut(table01, "May", "5th month"); + HashTablePut(table01, "June", "6th month"); + HashTablePut(table01, "July", "7th month"); + HashTablePut(table01, "August", "8th month"); + HashTablePut(table01, "September", "9th month"); + HashTablePut(table01, "October", "10th month"); + HashTablePut(table01, "November", "11th month"); + HashTablePut(table01, "December", "12th month"); + HashTableDisplay(table01); + + HashTableReplace(table01, "December", "The last month of the year"); + HashTableReplace(table01, "February", "The second month of the year"); + HashTableReplace(table01, "November", "Almost at the end of the year"); + HashTableDisplay(table01); + + char* string = HashTableGet(table01, "December"); + printf("\n*** %s = %s ***\n\n", "December", string); + free(string); + + // SECOND HT - Use the first and second key characters + + HashTable* table02 = HashTableCreate(17, hash2); + + HashTablePut(table02, "January", "1st month of the year"); + HashTablePut(table02, "February", "2nd month of the year"); + HashTablePut(table02, "March", "3rd month"); + HashTablePut(table02, "April", "4th month"); + HashTablePut(table02, "May", "5th month"); + HashTablePut(table02, "June", "6th month"); + HashTablePut(table02, "July", "7th month"); + HashTablePut(table02, "August", "8th month"); + HashTablePut(table02, "September", "9th month"); + HashTablePut(table02, "October", "10th month"); + HashTablePut(table02, "November", "11th month"); + HashTablePut(table02, "December", "12th month"); + HashTableDisplay(table02); + + HashTableRemove(table02, "January"); + HashTableRemove(table02, "February"); + HashTableRemove(table02, "March"); + HashTableRemove(table02, "April"); + HashTableDisplay(table02); + + HashTableRemove(table02, "May"); + HashTableRemove(table02, "June"); + HashTableRemove(table02, "July"); + HashTableRemove(table02, "August"); + HashTableDisplay(table02); + + HashTableRemove(table02, "September"); + HashTableRemove(table02, "October"); + HashTableRemove(table02, "November"); + HashTableRemove(table02, "December"); + HashTableDisplay(table02); + + // DESTROYING + + HashTableDestroy(&table01); + HashTableDestroy(&table02); + + // return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/HashTable.c b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/HashTable.c new file mode 100644 index 0000000..ecc2178 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/HashTable.c @@ -0,0 +1,238 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table using Separate Chaining +// Key and Value are STRINGS - To simplify the example +// + +#include "HashTable.h" + +#include +#include +#include +#include + +#include "SortedList.h" + +struct _HashTableBin { + char* key; + char* value; +}; + +struct _HashTableHeader { + unsigned int size; + unsigned int numBins; + hashFunction hashF; + List** table; +}; + +// The comparator: to compare a key (*p1) with the key on the list bin (*p2) + +int comparator(const void* p1, const void* p2) { + return strcmp(((struct _HashTableBin*)p1)->key, + ((struct _HashTableBin*)p2)->key); +} + +// Auxiliary functions for experimenting + +unsigned int hash1(const char* key) { + assert(strlen(key) > 0); + return key[0]; +} + +unsigned int hash2(const char* key) { + assert(strlen(key) > 0); + if (strlen(key) == 1) return key[0]; + return key[0] + key[1]; +} + +// TAD Functions + +HashTable* HashTableCreate(unsigned int size, hashFunction hashF) { + assert(size > 0); + HashTable* hTable = (HashTable*)malloc(sizeof(struct _HashTableHeader)); + assert(hTable != NULL); + hTable->table = (List**)malloc(size * sizeof(List*)); + assert(hTable->table != NULL); + + hTable->size = size; + hTable->numBins = 0; + hTable->hashF = hashF; + + for (unsigned int i = 0; i < size; i++) { + hTable->table[i] = ListCreate(comparator); + } + + return hTable; +} + +void HashTableDestroy(HashTable** p) { + assert(*p != NULL); + HashTable* t = *p; + + // For each chain + for (unsigned int i = 0; i < t->size; i++) { + List* l = t->table[i]; + // Free the HT bins of each list + while (ListIsEmpty(l) == 0) { + struct _HashTableBin* bin = ListRemoveHead(l); + free(bin->key); + free(bin->value); + free(bin); + } + // Destroy the list header + ListDestroy(&(t->table[i])); + } + + free(t->table); + free(t); + *p = NULL; +} + +// HashTable properties + +int HashTableIsEmpty(const HashTable* hashT) { return hashT->numBins == 0; } + +// Getters + +unsigned int HashTableGetNumberOfItems(const HashTable* hashT) { + return hashT->numBins; +} + +double HashTableGetLoadFactor(const HashTable* hashT) { + return (double)hashT->numBins / (double)hashT->size; +} + +// Operations with items + +// +// Search for the key +// If found, the list current node is updated +// +static int _searchKeyInList(List* l, char* key) { + if (ListIsEmpty(l)) { + return 0; + } + + // Needed for the comparator + // Shallow copy of the key: just the pointer + struct _HashTableBin searched; + searched.key = key; + + ListMoveToHead(l); + return ListSearch(l, &searched) != -1; +} + +int HashTableContains(const HashTable* hashT, char* key) { + unsigned int index = hashT->hashF(key) % hashT->size; + List* l = hashT->table[index]; + + return _searchKeyInList(l, key); +} + +char* HashTableGet(const HashTable* hashT, char* key) { + unsigned int index = hashT->hashF(key) % hashT->size; + List* l = hashT->table[index]; + + // Search and update current, if found + if (_searchKeyInList(l, key) == 0) { + return NULL; + } + + struct _HashTableBin* bin = ListGetCurrentItem(l); + + char* result = (char*)malloc(sizeof(char) * (1 + strlen(bin->value))); + strcpy(result, bin->value); + + return result; +} + +int HashTablePut(HashTable* hashT, char* key, char* value) { + unsigned int index = hashT->hashF(key) % hashT->size; + List* l = hashT->table[index]; + + if (_searchKeyInList(l, key) == 1) { + // FOUND, cannot be added to the table + return 0; + } + + // Does NOT BELONG to the table + // Insert a new bin in the list + + struct _HashTableBin* bin = (struct _HashTableBin*)malloc(sizeof(*bin)); + bin->key = (char*)malloc(sizeof(char) * (1 + strlen(key))); + strcpy(bin->key, key); + bin->value = (char*)malloc(sizeof(char) * (1 + strlen(value))); + strcpy(bin->value, value); + + ListInsert(l, bin); + hashT->numBins++; + + return 1; +} + +int HashTableReplace(const HashTable* hashT, char* key, char* value) { + unsigned int index = hashT->hashF(key) % hashT->size; + List* l = hashT->table[index]; + + // Search and update current, if found + if (_searchKeyInList(l, key) == 0) { + return 0; + } + + struct _HashTableBin* bin = ListGetCurrentItem(l); + + free(bin->value); + bin->value = (char*)malloc(sizeof(char) * (1 + strlen(value))); + strcpy(bin->value, value); + + return 1; +} + +int HashTableRemove(HashTable* hashT, char* key) { + unsigned int index = hashT->hashF(key) % hashT->size; + List* l = hashT->table[index]; + + // Search and update current, if found + if (_searchKeyInList(l, key) == 0) { + return 0; + } + + // Get rid of the bin + struct _HashTableBin* bin = ListGetCurrentItem(l); + free(bin->key); + free(bin->value); + free(bin); + + // Get rid of the list node + ListRemoveCurrent(l); + hashT->numBins--; + + return 1; +} + +// DISPLAYING on the console + +void HashTableDisplay(const HashTable* hashT) { + printf("---\n"); + printf("Size = %2d | Active = %2d\n", hashT->size, hashT->numBins); + for (unsigned int i = 0; i < hashT->size; i++) { + printf("%3d - ", i); + if (ListIsEmpty(hashT->table[i])) { + printf("\n"); + } else { + printf("\n"); + List* l = hashT->table[i]; + ListMoveToHead(l); + for (int i = 0; i < ListGetSize(l); i++) { + struct _HashTableBin* bin = ListGetCurrentItem(l); + unsigned int hashValue = hashT->hashF(bin->key); + printf(" Hash = %4d, (%s, %s)\n", hashValue, bin->key, bin->value); + ListMoveToNext(l); + } + } + } + printf("---\n"); +} diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/HashTable.h b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/HashTable.h new file mode 100644 index 0000000..aa5487f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/HashTable.h @@ -0,0 +1,54 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, May 2020, November 2023 +// +// Simple Hash Table using Separate Chaining +// Key and Value are STRINGS - To simplify the example +// + +#ifndef _HASH_TABLE_ +#define _HASH_TABLE_ + +typedef struct _HashTableHeader HashTable; + +typedef unsigned int (*hashFunction)(const char* key); + +// Auxiliary functions for experimenting + +unsigned int hash1(const char* key); +unsigned int hash2(const char* key); + +// TAD Functions + +HashTable* HashTableCreate(unsigned int capacity, hashFunction hashF); + +void HashTableDestroy(HashTable** p); + +// HashTable properties + +int HashTableIsEmpty(const HashTable* hashT); + +// Getters + +unsigned int HashTableGetNumberOfItems(const HashTable* hashT); + +double HashTableGetLoadFactor(const HashTable* hashT); + +// Operations with items + +int HashTableContains(const HashTable* hashT, char* key); + +char* HashTableGet(const HashTable* hashT, char* key); + +int HashTablePut(HashTable* hashT, char* key, char* value); + +int HashTableReplace(const HashTable* hashT, char* key, char* value); + +int HashTableRemove(HashTable* hashT, char* key); + +// DISPLAYING on the console + +void HashTableDisplay(const HashTable* hashT); + +#endif // _HASH_TABLE_ diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/SortedList.c b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/SortedList.c new file mode 100644 index 0000000..a3f8a5d --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/SortedList.c @@ -0,0 +1,340 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// SORTED LIST implementation based on an linked list +// + +// ***************** COMPLETAR AS FUNCOES !!! ******************* + +#include "SortedList.h" + +#include +#include + +struct _ListNode { + void* item; + struct _ListNode* next; +}; + +struct _SortedList { + int size; // current List size + struct _ListNode* head; // the head of the List + struct _ListNode* tail; // the tail of the List + struct _ListNode* current; // the current node + int currentPos; // the current node index + compFunc compare; +}; + +List* ListCreate(compFunc compF) { + List* l = (List*)malloc(sizeof(List)); + assert(l != NULL); + + l->size = 0; + l->head = NULL; + l->tail = NULL; + l->current = NULL; + l->currentPos = -1; // Default: before the head of the list + l->compare = compF; + return l; +} + +void ListDestroy(List** p) { + assert(*p != NULL); + List* l = *p; + + ListClear(l); + + free(l); + *p = NULL; +} + +void ListClear(List* l) { + assert(l != NULL); + + struct _ListNode* p = l->head; + struct _ListNode* aux; + + while (p != NULL) { + aux = p; + p = aux->next; + free(aux); + } + + l->size = 0; + l->head = NULL; + l->tail = NULL; + l->current = NULL; + l->currentPos = -1; // Default: before the head of the list +} + +int ListGetSize(const List* l) { + assert(l != NULL); + return l->size; +} + +int ListIsEmpty(const List* l) { + assert(l != NULL); + return (l->size == 0) ? 1 : 0; +} + +// Current node functions + +int ListGetCurrentIndex(const List* l) { + assert(l != NULL); + return l->currentPos; +} + +void* ListGetCurrentItem(const List* l) { + assert(l != NULL && l->current != NULL); + return l->current->item; +} + +void ListModifyCurrentValue(const List* l, void* p) { + assert(l != NULL && l->current != NULL); + l->current->item = p; +} + +// The move and search functions return 0 on success and -1 on failure (on +// success the current node is changed, on failure it is not changed) + +// Search +// +// starting at the current node, search for the first node with a value of *p +// on failure the current node is not changed +// +int ListSearch(List* l, const void* p) { + int i = (l->currentPos < 0) ? 0 : l->currentPos; + + struct _ListNode* sn = (l->currentPos < 0) ? l->head : l->current; + + while (i < l->size && l->compare(p, sn->item) > 0) { + i++; + sn = sn->next; + } + + if (i == l->size) { + return -1; + } // failure + + if (l->compare(p, sn->item) < 0) { + return -1; + } // failure + + l->current = sn; + l->currentPos = i; + + return 0; // success +} + +// Move to functions + +int ListMove(List* l, int newPos) { + if (newPos < -1 || newPos > l->size) { + return -1; + } // failure + + if (newPos == -1 || newPos == l->size) { + l->current = NULL; + } else if (newPos == 0) { + l->current = l->head; + } else if (newPos == l->size - 1) { + l->current = l->tail; + } else { + if (l->currentPos == -1 || l->currentPos == l->size || + newPos < l->currentPos) { + l->current = l->head; + l->currentPos = 0; + } + + for (int i = l->currentPos; i < newPos; i++) { + l->current = l->current->next; + } + } + l->currentPos = newPos; + + return 0; // success +} + +int ListMoveToNext(List* l) { return ListMove(l, l->currentPos + 1); } + +int ListMoveToPrevious(List* l) { return ListMove(l, l->currentPos - 1); } + +int ListMoveToHead(List* l) { return ListMove(l, 0); } + +int ListMoveToTail(List* l) { return ListMove(l, l->size - 1); } + +// Insert function + +// +// insert a node +// the current node is not changed +// return 0 on success +// return -1 on failure +// +int ListInsert(List* l, void* p) { + struct _ListNode* sn = (struct _ListNode*)malloc(sizeof(struct _ListNode)); + assert(sn != NULL); + sn->item = p; + sn->next = NULL; + + // Empty list + if (l->size == 0) { + l->head = l->tail = sn; + l->size = 1; + return 0; + } + + // Search + + int i = 0; + struct _ListNode* prev = NULL; + struct _ListNode* aux = l->head; + + while (i < l->size && l->compare(p, aux->item) > 0) { + i++; + prev = aux; + aux = aux->next; + } + + if (i == l->size) { // Append at the tail + l->tail->next = sn; + l->tail = sn; + l->size++; + return 0; + } + + if (l->compare(p, aux->item) == 0) { // Already exists !! + free(sn); + return -1; + } // failure + + if (i == 0) { // Append at the head + sn->next = l->head; + l->head = sn; + l->size++; + if (l->currentPos >= 0) { + l->currentPos++; + } + return 0; + } + + sn->next = aux; + prev->next = sn; + l->size++; + if (l->currentPos >= i) { + l->currentPos++; + } + + return 0; +} + +// Remove functions + +// +// remove the head of the list and make its next node the new head +// if the current node is the head, it is replaced by its next node +// +void* ListRemoveHead(List* l) { + assert(l->size > 0); + if (l->current == l->head) { + l->current = l->head->next; + l->currentPos++; + } + if (l->size == 1) { + void* p = l->head->item; + free(l->head); + l->head = NULL; + l->tail = NULL; + l->size = 0; + if (l->currentPos > 0) l->currentPos = 0; + return p; + } else { + struct _ListNode* sn = l->head->next; + void* p = l->head->item; + free(l->head); + l->head = sn; + if (l->currentPos > 0) l->currentPos--; + l->size--; + return p; + } +} + +// +// remove the tail of the list and make its previous node the new tail +// if the current node is the tail, it is replaced by it by its next node +// +void* ListRemoveTail(List* l) { + assert(l->size > 0); + if (l->current == l->tail) { + l->current = NULL; + l->currentPos++; + } + if (l->size == 1) { + void* p = l->head->item; + free(l->head); + l->head = NULL; + l->tail = NULL; + l->current = NULL; + if (l->currentPos > 0) l->currentPos = 0; + l->size = 0; + return p; + } else { + struct _ListNode* sn = l->head; + while (sn->next != l->tail) sn = sn->next; + sn->next = NULL; + void* p = l->tail->item; + free(l->tail); + l->tail = sn; + if (l->currentPos == l->size) l->currentPos--; + l->size--; + return p; + } +} + +// +// remove the current node and make its next node the current node +// +void* ListRemoveCurrent(List* l) { + assert(l->currentPos >= 0 && l->currentPos < l->size); + if (l->currentPos == 0) + return ListRemoveHead(l); + else if (l->currentPos == l->size - 1) + return ListRemoveTail(l); + else { + struct _ListNode* sn = l->head; + while (sn->next != l->current) sn = sn->next; + sn->next = l->current->next; + void* p = l->current->item; + free(l->current); + l->current = sn->next; + l->size--; + return p; + } +} + +// Tests + +void ListTestInvariants(const List* l) { + assert(l->size >= 0); + if (l->size == 0) + assert(l->head == NULL && l->tail == NULL); + else + assert(l->head != NULL && l->tail != NULL); + if (l->size == 1) assert(l->head == l->tail); + assert(-1 <= l->currentPos && l->currentPos <= l->size); + if (l->currentPos == -1 || l->currentPos == l->size) + assert(l->current == NULL); + struct _ListNode* sn = l->head; + for (int i = 0; i < l->size; i++) { + if (i == l->size - 1) + assert(sn == l->tail && sn->next == NULL); + else + assert(sn->next != NULL); + if (i == l->currentPos) assert(sn == l->current); + sn = sn->next; + } +} diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/SortedList.h b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/SortedList.h new file mode 100644 index 0000000..fda30b8 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/SortedList.h @@ -0,0 +1,70 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// SORTED LIST implementation based on a linked list +// + +#ifndef _SORTED_LIST_ +#define _SORTED_LIST_ + +typedef struct _SortedList List; +typedef int (*compFunc)(const void* p1, const void* p2); + +List* ListCreate(compFunc compF); + +void ListDestroy(List** p); + +void ListClear(List* l); + +int ListGetSize(const List* l); + +int ListIsEmpty(const List* l); + +// Current node functions + +int ListGetCurrentIndex(const List* l); + +void* ListGetCurrentItem(const List* l); + +void ListModifyCurrentItem(const List* l, void* p); + +// The move and search functions return 0 on success and -1 on failure (on +// success the current node is changed, on failure it is not changed) + +// Search + +int ListSearch(List* l, const void* p); + +// Move to + +int ListMove(List* l, int newPos); + +int ListMoveToNext(List* l); + +int ListMoveToPrevious(List* l); + +int ListMoveToHead(List* l); + +int ListMoveToTail(List* l); + +// Insert + +int ListInsert(List* l, void* p); + +// Remove + +void* ListRemoveHead(List* l); + +void* ListRemoveTail(List* l); + +void* ListRemoveCurrent(List* l); + +// Tests + +void ListTestInvariants(const List* l); + +#endif // _SORTED_LIST_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/TO_DO.txt b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/TO_DO.txt new file mode 100644 index 0000000..d5e602f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema09/20_AED_Dicionarios_II/01_Separate_Chaining/TO_DO.txt @@ -0,0 +1,6 @@ + +Implement RESIZING + REHASHING + +When the Load Factor N/M reaches 8, double the table size. + +When the Load Factor N/M reaches 2, halve the table siize. \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema09/20_AED__Dicionarios_II.pdf b/2ano/1semestre/aed/teoricas/tema09/20_AED__Dicionarios_II.pdf new file mode 100644 index 0000000..c67898b Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema09/20_AED__Dicionarios_II.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/.gitignore b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/.gitignore new file mode 100644 index 0000000..872134c --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/.gitignore @@ -0,0 +1 @@ +GRAFOS_EM_FICHEIRO diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Graph.c b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Graph.c new file mode 100644 index 0000000..541f9f1 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Graph.c @@ -0,0 +1,458 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - June 2021, Nov 2023 +// +// Graph - Using a list of adjacency lists representation +// + +#include "Graph.h" + +#include +#include +#include + +#include "SortedList.h" + +struct _Vertex { + unsigned int id; + unsigned int inDegree; + unsigned int outDegree; + List* edgesList; +}; + +struct _Edge { + unsigned int adjVertex; + double weight; +}; + +struct _GraphHeader { + int isDigraph; + int isComplete; + int isWeighted; + unsigned int numVertices; + unsigned int numEdges; + List* verticesList; +}; + +// The comparator for the VERTICES LIST + +int graphVerticesComparator(const void* p1, const void* p2) { + unsigned int v1 = ((struct _Vertex*)p1)->id; + unsigned int v2 = ((struct _Vertex*)p2)->id; + int d = v1 - v2; + return (d > 0) - (d < 0); +} + +// The comparator for the EDGES LISTS + +int graphEdgesComparator(const void* p1, const void* p2) { + unsigned int v1 = ((struct _Edge*)p1)->adjVertex; + unsigned int v2 = ((struct _Edge*)p2)->adjVertex; + int d = v1 - v2; + return (d > 0) - (d < 0); +} + +Graph* GraphCreate(unsigned int numVertices, int isDigraph, int isWeighted) { + Graph* g = (Graph*)malloc(sizeof(struct _GraphHeader)); + if (g == NULL) abort(); + + g->isDigraph = isDigraph; + g->isComplete = 0; + g->isWeighted = isWeighted; + + g->numVertices = numVertices; + g->numEdges = 0; + + g->verticesList = ListCreate(graphVerticesComparator); + + for (unsigned int i = 0; i < numVertices; i++) { + struct _Vertex* v = (struct _Vertex*)malloc(sizeof(struct _Vertex)); + if (v == NULL) abort(); + + v->id = i; + v->inDegree = 0; + v->outDegree = 0; + + v->edgesList = ListCreate(graphEdgesComparator); + + ListInsert(g->verticesList, v); + } + + assert(g->numVertices == ListGetSize(g->verticesList)); + + return g; +} + +Graph* GraphCreateComplete(unsigned int numVertices, int isDigraph) { + Graph* g = GraphCreate(numVertices, isDigraph, 0); + + g->isComplete = 1; + + List* vertices = g->verticesList; + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + struct _Vertex* v = ListGetCurrentItem(vertices); + List* edges = v->edgesList; + for (unsigned int j = 0; j < g->numVertices; j++) { + if (i == j) { + continue; + } + struct _Edge* new = (struct _Edge*)malloc(sizeof(struct _Edge)); + if (new == NULL) abort(); + new->adjVertex = j; + new->weight = 1; + + ListInsert(edges, new); + } + if (g->isDigraph) { + v->inDegree = g->numVertices - 1; + v->outDegree = g->numVertices - 1; + } else { + v->outDegree = g->numVertices - 1; + } + } + if (g->isDigraph) { + g->numEdges = numVertices * (numVertices - 1); + } else { + g->numEdges = numVertices * (numVertices - 1) / 2; + } + + return g; +} + +void GraphDestroy(Graph** p) { + assert(*p != NULL); + Graph* g = *p; + + List* vertices = g->verticesList; + if (ListIsEmpty(vertices) == 0) { + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + struct _Vertex* v = ListGetCurrentItem(vertices); + + List* edges = v->edgesList; + if (ListIsEmpty(edges) == 0) { + unsigned int i = 0; + ListMoveToHead(edges); + for (; i < ListGetSize(edges); ListMoveToNext(edges), i++) { + struct _Edge* e = ListGetCurrentItem(edges); + free(e); + } + } + ListDestroy(&(v->edgesList)); + free(v); + } + } + + ListDestroy(&(g->verticesList)); + free(g); + + *p = NULL; +} + +Graph* GraphCopy(const Graph* g) { + // COMPLETAR !! + + return NULL; +} + +Graph* GraphFromFile(FILE* f) { + // COMPLETAR !! + + return NULL; +} + +// Graph + +int GraphIsDigraph(const Graph* g) { return g->isDigraph; } + +int GraphIsComplete(const Graph* g) { return g->isComplete; } + +int GraphIsWeighted(const Graph* g) { return g->isWeighted; } + +unsigned int GraphGetNumVertices(const Graph* g) { return g->numVertices; } + +unsigned int GraphGetNumEdges(const Graph* g) { return g->numEdges; } + +// +// For a graph +// +double GraphGetAverageDegree(const Graph* g) { + assert(g->isDigraph == 0); + return 2.0 * (double)g->numEdges / (double)g->numVertices; +} + +static unsigned int _GetMaxDegree(const Graph* g) { + List* vertices = g->verticesList; + if (ListIsEmpty(vertices)) return 0; + + unsigned int maxDegree = 0; + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + struct _Vertex* v = ListGetCurrentItem(vertices); + if (v->outDegree > maxDegree) { + maxDegree = v->outDegree; + } + } + return maxDegree; +} + +// +// For a graph +// +unsigned int GraphGetMaxDegree(const Graph* g) { + assert(g->isDigraph == 0); + return _GetMaxDegree(g); +} + +// +// For a digraph +// +unsigned int GraphGetMaxOutDegree(const Graph* g) { + assert(g->isDigraph == 1); + return _GetMaxDegree(g); +} + +// Vertices + +// +// returns an array of size (outDegree + 1) +// element 0, stores the number of adjacent vertices +// and is followed by indices of the adjacent vertices +// +unsigned int* GraphGetAdjacentsTo(const Graph* g, unsigned int v) { + assert(v < g->numVertices); + + // Node in the list of vertices + List* vertices = g->verticesList; + ListMove(vertices, v); + struct _Vertex* vPointer = ListGetCurrentItem(vertices); + unsigned int numAdjVertices = vPointer->outDegree; + + unsigned int* adjacent = + (unsigned int*)calloc(1 + numAdjVertices, sizeof(unsigned int)); + + if (numAdjVertices > 0) { + adjacent[0] = numAdjVertices; + List* adjList = vPointer->edgesList; + ListMoveToHead(adjList); + for (unsigned int i = 0; i < numAdjVertices; ListMoveToNext(adjList), i++) { + struct _Edge* ePointer = ListGetCurrentItem(adjList); + adjacent[i + 1] = ePointer->adjVertex; + } + } + + return adjacent; +} + +// +// returns an array of size (outDegree + 1) +// element 0, stores the number of adjacent vertices +// and is followed by the distances to the adjacent vertices +// +double* GraphGetDistancesToAdjacents(const Graph* g, unsigned int v) { + assert(v < g->numVertices); + + // Node in the list of vertices + List* vertices = g->verticesList; + ListMove(vertices, v); + struct _Vertex* vPointer = ListGetCurrentItem(vertices); + unsigned int numAdjVertices = vPointer->outDegree; + + double* distance = (double*)calloc(1 + numAdjVertices, sizeof(double)); + + if (numAdjVertices > 0) { + distance[0] = numAdjVertices; + List* adjList = vPointer->edgesList; + ListMoveToHead(adjList); + for (unsigned int i = 0; i < numAdjVertices; ListMoveToNext(adjList), i++) { + struct _Edge* ePointer = ListGetCurrentItem(adjList); + distance[i + 1] = ePointer->weight; + } + } + + return distance; +} + +// +// For a graph +// +unsigned int GraphGetVertexDegree(Graph* g, unsigned int v) { + assert(g->isDigraph == 0); + assert(v < g->numVertices); + + ListMove(g->verticesList, v); + struct _Vertex* p = ListGetCurrentItem(g->verticesList); + + return p->outDegree; +} + +// +// For a digraph +// +unsigned int GraphGetVertexOutDegree(Graph* g, unsigned int v) { + assert(g->isDigraph == 1); + assert(v < g->numVertices); + + ListMove(g->verticesList, v); + struct _Vertex* p = ListGetCurrentItem(g->verticesList); + + return p->outDegree; +} + +// +// For a digraph +// +unsigned int GraphGetVertexInDegree(Graph* g, unsigned int v) { + assert(g->isDigraph == 1); + assert(v < g->numVertices); + + ListMove(g->verticesList, v); + struct _Vertex* p = ListGetCurrentItem(g->verticesList); + + return p->inDegree; +} + +// Edges + +static int _addEdge(Graph* g, unsigned int v, unsigned int w, double weight) { + struct _Edge* edge = (struct _Edge*)malloc(sizeof(struct _Edge)); + edge->adjVertex = w; + edge->weight = weight; + + ListMove(g->verticesList, v); + struct _Vertex* vertex = ListGetCurrentItem(g->verticesList); + int result = ListInsert(vertex->edgesList, edge); + + if (result == -1) { + return 0; + } else { + g->numEdges++; + vertex->outDegree++; + + ListMove(g->verticesList, w); + struct _Vertex* destVertex = ListGetCurrentItem(g->verticesList); + destVertex->inDegree++; + } + + if (g->isDigraph == 0) { + // Bidirectional edge + struct _Edge* edge = (struct _Edge*)malloc(sizeof(struct _Edge)); + edge->adjVertex = v; + edge->weight = weight; + + ListMove(g->verticesList, w); + struct _Vertex* vertex = ListGetCurrentItem(g->verticesList); + result = ListInsert(vertex->edgesList, edge); + + if (result == -1) { + return 0; + } else { + // g->numEdges++; // Do not count the same edge twice on a undirected + // graph !! + vertex->outDegree++; + } + } + + return 1; +} + +int GraphAddEdge(Graph* g, unsigned int v, unsigned int w) { + assert(g->isWeighted == 0); + assert(v != w); + assert(v < g->numVertices); + assert(w < g->numVertices); + + return _addEdge(g, v, w, 1.0); +} + +int GraphAddWeightedEdge(Graph* g, unsigned int v, unsigned int w, + double weight) { + assert(g->isWeighted == 1); + assert(v != w); + assert(v < g->numVertices); + assert(w < g->numVertices); + + return _addEdge(g, v, w, weight); +} + +int GraphRemoveEdge(Graph* g, unsigned int v, unsigned int w) { + // COMPLETAR !! + + return 0; +} + +// CHECKING + +int GraphCheckInvariants(const Graph* g) { + // COMPLETAR !! + + return 0; +} + +// DISPLAYING on the console + +void GraphDisplay(const Graph* g) { + printf("---\n"); + if (g->isWeighted) { + printf("Weighted "); + } + if (g->isComplete) { + printf("COMPLETE "); + } + if (g->isDigraph) { + printf("Digraph\n"); + printf("Max Out-Degree = %d\n", GraphGetMaxOutDegree(g)); + } else { + printf("Graph\n"); + printf("Max Degree = %d\n", GraphGetMaxDegree(g)); + } + printf("Vertices = %2d | Edges = %2d\n", g->numVertices, g->numEdges); + + List* vertices = g->verticesList; + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + printf("%2d ->", i); + struct _Vertex* v = ListGetCurrentItem(vertices); + if (ListIsEmpty(v->edgesList)) { + printf("\n"); + } else { + List* edges = v->edgesList; + unsigned int i = 0; + ListMoveToHead(edges); + for (; i < ListGetSize(edges); ListMoveToNext(edges), i++) { + struct _Edge* e = ListGetCurrentItem(edges); + if (g->isWeighted) { + printf(" %2d(%4.2f)", e->adjVertex, e->weight); + } else { + printf(" %2d", e->adjVertex); + } + } + printf("\n"); + } + } + printf("---\n"); +} + +void GraphListAdjacents(const Graph* g, unsigned int v) { + printf("---\n"); + + unsigned int* array = GraphGetAdjacentsTo(g, v); + + printf("Vertex %d has %d adjacent vertices -> ", v, array[0]); + + for (unsigned int i = 1; i <= array[0]; i++) { + printf("%d ", array[i]); + } + + printf("\n"); + + free(array); + + printf("---\n"); +} diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Graph.h b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Graph.h new file mode 100644 index 0000000..934448f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Graph.h @@ -0,0 +1,94 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - June 2021, Nov 2023 +// +// Graph - Using a list of adjacency lists representation +// + +#ifndef _GRAPH_ +#define _GRAPH_ + +#include + +typedef struct _GraphHeader Graph; + +Graph* GraphCreate(unsigned int numVertices, int isDigraph, int isWeighted); + +Graph* GraphCreateComplete(unsigned int numVertices, int isDigraph); + +void GraphDestroy(Graph** p); + +Graph* GraphCopy(const Graph* g); + +Graph* GraphFromFile(FILE* f); + +// Graph + +int GraphIsDigraph(const Graph* g); + +int GraphIsComplete(const Graph* g); + +int GraphIsWeighted(const Graph* g); + +unsigned int GraphGetNumVertices(const Graph* g); + +unsigned int GraphGetNumEdges(const Graph* g); + +// +// For a graph +// +double GraphGetAverageDegree(const Graph* g); + +// +// For a graph +// +unsigned int GraphGetMaxDegree(const Graph* g); + +// +// For a digraph +// +unsigned int GraphGetMaxOutDegree(const Graph* g); + +// Vertices + +unsigned int* GraphGetAdjacentsTo(const Graph* g, unsigned int v); + +// Vertices distances +double* GraphGetDistancesToAdjacents(const Graph* g, unsigned int v); + +// +// For a graph +// +unsigned int GraphGetVertexDegree(Graph* g, unsigned int v); + +// +// For a digraph +// +unsigned int GraphGetVertexOutDegree(Graph* g, unsigned int v); + +// +// For a digraph +// +unsigned int GraphGetVertexInDegree(Graph* g, unsigned int v); + +// Edges + +int GraphAddEdge(Graph* g, unsigned int v, unsigned int w); + +int GraphAddWeightedEdge(Graph* g, unsigned int v, unsigned int w, + double weight); + +int GraphRemoveEdge(Graph* g, unsigned int v, unsigned int w); + +// CHECKING + +int GraphCheckInvariants(const Graph* g); + +// DISPLAYING on the console + +void GraphDisplay(const Graph* g); + +void GraphListAdjacents(const Graph* g, unsigned int v); + +#endif // _GRAPH_ diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Makefile b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Makefile new file mode 100644 index 0000000..d8bc58e --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/Makefile @@ -0,0 +1,26 @@ +# To compile all programs, run: +# make +# +# AED, ua, 2023 + +CFLAGS += -g -Wall -Wextra + +TARGETS = example1 + +all: $(TARGETS) + +example1: example1.o Graph.o SortedList.o + +# Dependencies of source files (obtained with gcc -MM) + +example1.o: example1.c Graph.h + +Graph.o: Graph.c Graph.h SortedList.h + +SortedList.o: SortedList.c SortedList.h + +clean: + rm -f *.o + rm -f $(TARGETS) + + diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/SortedList.c b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/SortedList.c new file mode 100644 index 0000000..9d65ca7 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/SortedList.c @@ -0,0 +1,340 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// SORTED LIST implementation based on an linked list +// + +// ***************** COMPLETAR AS FUNCOES !!! ******************* + +#include "SortedList.h" + +#include +#include + +struct _ListNode { + void* item; + struct _ListNode* next; +}; + +struct _SortedList { + int size; // current List size + struct _ListNode* head; // the head of the List + struct _ListNode* tail; // the tail of the List + struct _ListNode* current; // the current node + int currentPos; // the current node index + compFunc compare; +}; + +List* ListCreate(compFunc compF) { + List* l = (List*)malloc(sizeof(List)); + assert(l != NULL); + + l->size = 0; + l->head = NULL; + l->tail = NULL; + l->current = NULL; + l->currentPos = -1; // Default: before the head of the list + l->compare = compF; + return l; +} + +void ListDestroy(List** p) { + assert(*p != NULL); + List* l = *p; + + ListClear(l); + + free(l); + *p = NULL; +} + +void ListClear(List* l) { + assert(l != NULL); + + struct _ListNode* p = l->head; + struct _ListNode* aux; + + while (p != NULL) { + aux = p; + p = aux->next; + free(aux); + } + + l->size = 0; + l->head = NULL; + l->tail = NULL; + l->current = NULL; + l->currentPos = -1; // Default: before the head of the list +} + +unsigned int ListGetSize(const List* l) { + assert(l != NULL); + return l->size; +} + +int ListIsEmpty(const List* l) { + assert(l != NULL); + return (l->size == 0) ? 1 : 0; +} + +// Current node functions + +int ListGetCurrentIndex(const List* l) { + assert(l != NULL); + return l->currentPos; +} + +void* ListGetCurrentItem(const List* l) { + assert(l != NULL && l->current != NULL); + return l->current->item; +} + +void ListModifyCurrentValue(const List* l, void* p) { + assert(l != NULL && l->current != NULL); + l->current->item = p; +} + +// The move and search functions return 0 on success and -1 on failure (on +// success the current node is changed, on failure it is not changed) + +// Search +// +// starting at the current node, search for the first node with a value of *p +// on failure the current node is not changed +// +int ListSearch(List* l, const void* p) { + int i = (l->currentPos < 0) ? 0 : l->currentPos; + + struct _ListNode* sn = (l->currentPos < 0) ? l->head : l->current; + + while (i < l->size && l->compare(p, sn->item) > 0) { + i++; + sn = sn->next; + } + + if (i == l->size) { + return -1; + } // failure + + if (l->compare(p, sn->item) < 0) { + return -1; + } // failure + + l->current = sn; + l->currentPos = i; + + return 0; // success +} + +// Move to functions + +int ListMove(List* l, int newPos) { + if (newPos < -1 || newPos > l->size) { + return -1; + } // failure + + if (newPos == -1 || newPos == l->size) { + l->current = NULL; + } else if (newPos == 0) { + l->current = l->head; + } else if (newPos == l->size - 1) { + l->current = l->tail; + } else { + if (l->currentPos == -1 || l->currentPos == l->size || + newPos < l->currentPos) { + l->current = l->head; + l->currentPos = 0; + } + + for (int i = l->currentPos; i < newPos; i++) { + l->current = l->current->next; + } + } + l->currentPos = newPos; + + return 0; // success +} + +int ListMoveToNext(List* l) { return ListMove(l, l->currentPos + 1); } + +int ListMoveToPrevious(List* l) { return ListMove(l, l->currentPos - 1); } + +int ListMoveToHead(List* l) { return ListMove(l, 0); } + +int ListMoveToTail(List* l) { return ListMove(l, l->size - 1); } + +// Insert function + +// +// insert a node +// the current node is not changed +// return 0 on success +// return -1 on failure +// +int ListInsert(List* l, void* p) { + struct _ListNode* sn = (struct _ListNode*)malloc(sizeof(struct _ListNode)); + assert(sn != NULL); + sn->item = p; + sn->next = NULL; + + // Empty list + if (l->size == 0) { + l->head = l->tail = sn; + l->size = 1; + return 0; + } + + // Search + + int i = 0; + struct _ListNode* prev = NULL; + struct _ListNode* aux = l->head; + + while (i < l->size && l->compare(p, aux->item) > 0) { + i++; + prev = aux; + aux = aux->next; + } + + if (i == l->size) { // Append at the tail + l->tail->next = sn; + l->tail = sn; + l->size++; + return 0; + } + + if (l->compare(p, aux->item) == 0) { // Already exists !! + free(sn); + return -1; + } // failure + + if (i == 0) { // Append at the head + sn->next = l->head; + l->head = sn; + l->size++; + if (l->currentPos >= 0) { + l->currentPos++; + } + return 0; + } + + sn->next = aux; + prev->next = sn; + l->size++; + if (l->currentPos >= i) { + l->currentPos++; + } + + return 0; +} + +// Remove functions + +// +// remove the head of the list and make its next node the new head +// if the current node is the head, it is replaced by its next node +// +void* ListRemoveHead(List* l) { + assert(l->size > 0); + if (l->current == l->head) { + l->current = l->head->next; + l->currentPos++; + } + if (l->size == 1) { + void* p = l->head->item; + free(l->head); + l->head = NULL; + l->tail = NULL; + l->size = 0; + if (l->currentPos > 0) l->currentPos = 0; + return p; + } else { + struct _ListNode* sn = l->head->next; + void* p = l->head->item; + free(l->head); + l->head = sn; + if (l->currentPos > 0) l->currentPos--; + l->size--; + return p; + } +} + +// +// remove the tail of the list and make its previous node the new tail +// if the current node is the tail, it is replaced by it by its next node +// +void* ListRemoveTail(List* l) { + assert(l->size > 0); + if (l->current == l->tail) { + l->current = NULL; + l->currentPos++; + } + if (l->size == 1) { + void* p = l->head->item; + free(l->head); + l->head = NULL; + l->tail = NULL; + l->current = NULL; + if (l->currentPos > 0) l->currentPos = 0; + l->size = 0; + return p; + } else { + struct _ListNode* sn = l->head; + while (sn->next != l->tail) sn = sn->next; + sn->next = NULL; + void* p = l->tail->item; + free(l->tail); + l->tail = sn; + if (l->currentPos == l->size) l->currentPos--; + l->size--; + return p; + } +} + +// +// remove the current node and make its next node the current node +// +void* ListRemoveCurrent(List* l) { + assert(l->currentPos >= 0 && l->currentPos < l->size); + if (l->currentPos == 0) + return ListRemoveHead(l); + else if (l->currentPos == l->size - 1) + return ListRemoveTail(l); + else { + struct _ListNode* sn = l->head; + while (sn->next != l->current) sn = sn->next; + sn->next = l->current->next; + void* p = l->current->item; + free(l->current); + l->current = sn->next; + l->size--; + return p; + } +} + +// Tests + +void ListTestInvariants(const List* l) { + assert(l->size >= 0); + if (l->size == 0) + assert(l->head == NULL && l->tail == NULL); + else + assert(l->head != NULL && l->tail != NULL); + if (l->size == 1) assert(l->head == l->tail); + assert(-1 <= l->currentPos && l->currentPos <= l->size); + if (l->currentPos == -1 || l->currentPos == l->size) + assert(l->current == NULL); + struct _ListNode* sn = l->head; + for (int i = 0; i < l->size; i++) { + if (i == l->size - 1) + assert(sn == l->tail && sn->next == NULL); + else + assert(sn->next != NULL); + if (i == l->currentPos) assert(sn == l->current); + sn = sn->next; + } +} diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/SortedList.h b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/SortedList.h new file mode 100644 index 0000000..67b77db --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/SortedList.h @@ -0,0 +1,70 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// SORTED LIST implementation based on a linked list +// + +#ifndef _SORTED_LIST_ +#define _SORTED_LIST_ + +typedef struct _SortedList List; +typedef int (*compFunc)(const void* p1, const void* p2); + +List* ListCreate(compFunc compF); + +void ListDestroy(List** p); + +void ListClear(List* l); + +unsigned int ListGetSize(const List* l); + +int ListIsEmpty(const List* l); + +// Current node functions + +int ListGetCurrentIndex(const List* l); + +void* ListGetCurrentItem(const List* l); + +void ListModifyCurrentItem(const List* l, void* p); + +// The move and search functions return 0 on success and -1 on failure (on +// success the current node is changed, on failure it is not changed) + +// Search + +int ListSearch(List* l, const void* p); + +// Move to + +int ListMove(List* l, int newPos); + +int ListMoveToNext(List* l); + +int ListMoveToPrevious(List* l); + +int ListMoveToHead(List* l); + +int ListMoveToTail(List* l); + +// Insert + +int ListInsert(List* l, void* p); + +// Remove + +void* ListRemoveHead(List* l); + +void* ListRemoveTail(List* l); + +void* ListRemoveCurrent(List* l); + +// Tests + +void ListTestInvariants(const List* l); + +#endif // _SORTED_LIST_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/example1.c b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/example1.c new file mode 100644 index 0000000..d1ae3f2 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/21_AED_Grafos_I/example1.c @@ -0,0 +1,50 @@ +// +// Joaquim Madeira, AlgC, June 2021 +// João Manuel Rodrigues, AlgC, June 2021 +// +// Graph EXAMPLE +// + +#include "Graph.h" + +int main(void) { + // What kind of graph is g01? + Graph* g01 = GraphCreate(6, 0, 0); + GraphAddEdge(g01, 1, 2); + GraphAddEdge(g01, 1, 4); + GraphAddEdge(g01, 3, 4); + printf("The first graph:\n"); + GraphDisplay(g01); + for (int i = 0; i < 6; i++) { + GraphListAdjacents(g01, i); + } + printf("Remove edge (1,2)\n"); + GraphDisplay(g01); + for (int i = 0; i < 6; i++) { + GraphListAdjacents(g01, i); + } + + Graph* dig01 = GraphCreate(6, 1, 0); + GraphAddEdge(dig01, 1, 2); + GraphAddEdge(dig01, 1, 4); + GraphAddEdge(dig01, 3, 4); + printf("The second graph:\n"); + GraphDisplay(dig01); + printf("Remove edge (1,2)\n"); + GraphDisplay(dig01); + + Graph* g03 = GraphCreate(6, 0, 1); + GraphAddWeightedEdge(g03, 1, 2, 3); + GraphAddWeightedEdge(g03, 1, 4, 5); + GraphAddWeightedEdge(g03, 3, 4, 10); + printf("The third graph:\n"); + GraphDisplay(g03); + printf("Remove edge (1,2)\n"); + GraphDisplay(g03); + + GraphDestroy(&g01); + GraphDestroy(&dig01); + GraphDestroy(&g03); + + return 0; +} diff --git a/2ano/1semestre/aed/teoricas/tema10/21_AED__Grafos_I.pdf b/2ano/1semestre/aed/teoricas/tema10/21_AED__Grafos_I.pdf new file mode 100644 index 0000000..4f22edb Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema10/21_AED__Grafos_I.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Graph.c b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Graph.c new file mode 100644 index 0000000..541f9f1 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Graph.c @@ -0,0 +1,458 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - June 2021, Nov 2023 +// +// Graph - Using a list of adjacency lists representation +// + +#include "Graph.h" + +#include +#include +#include + +#include "SortedList.h" + +struct _Vertex { + unsigned int id; + unsigned int inDegree; + unsigned int outDegree; + List* edgesList; +}; + +struct _Edge { + unsigned int adjVertex; + double weight; +}; + +struct _GraphHeader { + int isDigraph; + int isComplete; + int isWeighted; + unsigned int numVertices; + unsigned int numEdges; + List* verticesList; +}; + +// The comparator for the VERTICES LIST + +int graphVerticesComparator(const void* p1, const void* p2) { + unsigned int v1 = ((struct _Vertex*)p1)->id; + unsigned int v2 = ((struct _Vertex*)p2)->id; + int d = v1 - v2; + return (d > 0) - (d < 0); +} + +// The comparator for the EDGES LISTS + +int graphEdgesComparator(const void* p1, const void* p2) { + unsigned int v1 = ((struct _Edge*)p1)->adjVertex; + unsigned int v2 = ((struct _Edge*)p2)->adjVertex; + int d = v1 - v2; + return (d > 0) - (d < 0); +} + +Graph* GraphCreate(unsigned int numVertices, int isDigraph, int isWeighted) { + Graph* g = (Graph*)malloc(sizeof(struct _GraphHeader)); + if (g == NULL) abort(); + + g->isDigraph = isDigraph; + g->isComplete = 0; + g->isWeighted = isWeighted; + + g->numVertices = numVertices; + g->numEdges = 0; + + g->verticesList = ListCreate(graphVerticesComparator); + + for (unsigned int i = 0; i < numVertices; i++) { + struct _Vertex* v = (struct _Vertex*)malloc(sizeof(struct _Vertex)); + if (v == NULL) abort(); + + v->id = i; + v->inDegree = 0; + v->outDegree = 0; + + v->edgesList = ListCreate(graphEdgesComparator); + + ListInsert(g->verticesList, v); + } + + assert(g->numVertices == ListGetSize(g->verticesList)); + + return g; +} + +Graph* GraphCreateComplete(unsigned int numVertices, int isDigraph) { + Graph* g = GraphCreate(numVertices, isDigraph, 0); + + g->isComplete = 1; + + List* vertices = g->verticesList; + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + struct _Vertex* v = ListGetCurrentItem(vertices); + List* edges = v->edgesList; + for (unsigned int j = 0; j < g->numVertices; j++) { + if (i == j) { + continue; + } + struct _Edge* new = (struct _Edge*)malloc(sizeof(struct _Edge)); + if (new == NULL) abort(); + new->adjVertex = j; + new->weight = 1; + + ListInsert(edges, new); + } + if (g->isDigraph) { + v->inDegree = g->numVertices - 1; + v->outDegree = g->numVertices - 1; + } else { + v->outDegree = g->numVertices - 1; + } + } + if (g->isDigraph) { + g->numEdges = numVertices * (numVertices - 1); + } else { + g->numEdges = numVertices * (numVertices - 1) / 2; + } + + return g; +} + +void GraphDestroy(Graph** p) { + assert(*p != NULL); + Graph* g = *p; + + List* vertices = g->verticesList; + if (ListIsEmpty(vertices) == 0) { + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + struct _Vertex* v = ListGetCurrentItem(vertices); + + List* edges = v->edgesList; + if (ListIsEmpty(edges) == 0) { + unsigned int i = 0; + ListMoveToHead(edges); + for (; i < ListGetSize(edges); ListMoveToNext(edges), i++) { + struct _Edge* e = ListGetCurrentItem(edges); + free(e); + } + } + ListDestroy(&(v->edgesList)); + free(v); + } + } + + ListDestroy(&(g->verticesList)); + free(g); + + *p = NULL; +} + +Graph* GraphCopy(const Graph* g) { + // COMPLETAR !! + + return NULL; +} + +Graph* GraphFromFile(FILE* f) { + // COMPLETAR !! + + return NULL; +} + +// Graph + +int GraphIsDigraph(const Graph* g) { return g->isDigraph; } + +int GraphIsComplete(const Graph* g) { return g->isComplete; } + +int GraphIsWeighted(const Graph* g) { return g->isWeighted; } + +unsigned int GraphGetNumVertices(const Graph* g) { return g->numVertices; } + +unsigned int GraphGetNumEdges(const Graph* g) { return g->numEdges; } + +// +// For a graph +// +double GraphGetAverageDegree(const Graph* g) { + assert(g->isDigraph == 0); + return 2.0 * (double)g->numEdges / (double)g->numVertices; +} + +static unsigned int _GetMaxDegree(const Graph* g) { + List* vertices = g->verticesList; + if (ListIsEmpty(vertices)) return 0; + + unsigned int maxDegree = 0; + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + struct _Vertex* v = ListGetCurrentItem(vertices); + if (v->outDegree > maxDegree) { + maxDegree = v->outDegree; + } + } + return maxDegree; +} + +// +// For a graph +// +unsigned int GraphGetMaxDegree(const Graph* g) { + assert(g->isDigraph == 0); + return _GetMaxDegree(g); +} + +// +// For a digraph +// +unsigned int GraphGetMaxOutDegree(const Graph* g) { + assert(g->isDigraph == 1); + return _GetMaxDegree(g); +} + +// Vertices + +// +// returns an array of size (outDegree + 1) +// element 0, stores the number of adjacent vertices +// and is followed by indices of the adjacent vertices +// +unsigned int* GraphGetAdjacentsTo(const Graph* g, unsigned int v) { + assert(v < g->numVertices); + + // Node in the list of vertices + List* vertices = g->verticesList; + ListMove(vertices, v); + struct _Vertex* vPointer = ListGetCurrentItem(vertices); + unsigned int numAdjVertices = vPointer->outDegree; + + unsigned int* adjacent = + (unsigned int*)calloc(1 + numAdjVertices, sizeof(unsigned int)); + + if (numAdjVertices > 0) { + adjacent[0] = numAdjVertices; + List* adjList = vPointer->edgesList; + ListMoveToHead(adjList); + for (unsigned int i = 0; i < numAdjVertices; ListMoveToNext(adjList), i++) { + struct _Edge* ePointer = ListGetCurrentItem(adjList); + adjacent[i + 1] = ePointer->adjVertex; + } + } + + return adjacent; +} + +// +// returns an array of size (outDegree + 1) +// element 0, stores the number of adjacent vertices +// and is followed by the distances to the adjacent vertices +// +double* GraphGetDistancesToAdjacents(const Graph* g, unsigned int v) { + assert(v < g->numVertices); + + // Node in the list of vertices + List* vertices = g->verticesList; + ListMove(vertices, v); + struct _Vertex* vPointer = ListGetCurrentItem(vertices); + unsigned int numAdjVertices = vPointer->outDegree; + + double* distance = (double*)calloc(1 + numAdjVertices, sizeof(double)); + + if (numAdjVertices > 0) { + distance[0] = numAdjVertices; + List* adjList = vPointer->edgesList; + ListMoveToHead(adjList); + for (unsigned int i = 0; i < numAdjVertices; ListMoveToNext(adjList), i++) { + struct _Edge* ePointer = ListGetCurrentItem(adjList); + distance[i + 1] = ePointer->weight; + } + } + + return distance; +} + +// +// For a graph +// +unsigned int GraphGetVertexDegree(Graph* g, unsigned int v) { + assert(g->isDigraph == 0); + assert(v < g->numVertices); + + ListMove(g->verticesList, v); + struct _Vertex* p = ListGetCurrentItem(g->verticesList); + + return p->outDegree; +} + +// +// For a digraph +// +unsigned int GraphGetVertexOutDegree(Graph* g, unsigned int v) { + assert(g->isDigraph == 1); + assert(v < g->numVertices); + + ListMove(g->verticesList, v); + struct _Vertex* p = ListGetCurrentItem(g->verticesList); + + return p->outDegree; +} + +// +// For a digraph +// +unsigned int GraphGetVertexInDegree(Graph* g, unsigned int v) { + assert(g->isDigraph == 1); + assert(v < g->numVertices); + + ListMove(g->verticesList, v); + struct _Vertex* p = ListGetCurrentItem(g->verticesList); + + return p->inDegree; +} + +// Edges + +static int _addEdge(Graph* g, unsigned int v, unsigned int w, double weight) { + struct _Edge* edge = (struct _Edge*)malloc(sizeof(struct _Edge)); + edge->adjVertex = w; + edge->weight = weight; + + ListMove(g->verticesList, v); + struct _Vertex* vertex = ListGetCurrentItem(g->verticesList); + int result = ListInsert(vertex->edgesList, edge); + + if (result == -1) { + return 0; + } else { + g->numEdges++; + vertex->outDegree++; + + ListMove(g->verticesList, w); + struct _Vertex* destVertex = ListGetCurrentItem(g->verticesList); + destVertex->inDegree++; + } + + if (g->isDigraph == 0) { + // Bidirectional edge + struct _Edge* edge = (struct _Edge*)malloc(sizeof(struct _Edge)); + edge->adjVertex = v; + edge->weight = weight; + + ListMove(g->verticesList, w); + struct _Vertex* vertex = ListGetCurrentItem(g->verticesList); + result = ListInsert(vertex->edgesList, edge); + + if (result == -1) { + return 0; + } else { + // g->numEdges++; // Do not count the same edge twice on a undirected + // graph !! + vertex->outDegree++; + } + } + + return 1; +} + +int GraphAddEdge(Graph* g, unsigned int v, unsigned int w) { + assert(g->isWeighted == 0); + assert(v != w); + assert(v < g->numVertices); + assert(w < g->numVertices); + + return _addEdge(g, v, w, 1.0); +} + +int GraphAddWeightedEdge(Graph* g, unsigned int v, unsigned int w, + double weight) { + assert(g->isWeighted == 1); + assert(v != w); + assert(v < g->numVertices); + assert(w < g->numVertices); + + return _addEdge(g, v, w, weight); +} + +int GraphRemoveEdge(Graph* g, unsigned int v, unsigned int w) { + // COMPLETAR !! + + return 0; +} + +// CHECKING + +int GraphCheckInvariants(const Graph* g) { + // COMPLETAR !! + + return 0; +} + +// DISPLAYING on the console + +void GraphDisplay(const Graph* g) { + printf("---\n"); + if (g->isWeighted) { + printf("Weighted "); + } + if (g->isComplete) { + printf("COMPLETE "); + } + if (g->isDigraph) { + printf("Digraph\n"); + printf("Max Out-Degree = %d\n", GraphGetMaxOutDegree(g)); + } else { + printf("Graph\n"); + printf("Max Degree = %d\n", GraphGetMaxDegree(g)); + } + printf("Vertices = %2d | Edges = %2d\n", g->numVertices, g->numEdges); + + List* vertices = g->verticesList; + ListMoveToHead(vertices); + unsigned int i = 0; + for (; i < g->numVertices; ListMoveToNext(vertices), i++) { + printf("%2d ->", i); + struct _Vertex* v = ListGetCurrentItem(vertices); + if (ListIsEmpty(v->edgesList)) { + printf("\n"); + } else { + List* edges = v->edgesList; + unsigned int i = 0; + ListMoveToHead(edges); + for (; i < ListGetSize(edges); ListMoveToNext(edges), i++) { + struct _Edge* e = ListGetCurrentItem(edges); + if (g->isWeighted) { + printf(" %2d(%4.2f)", e->adjVertex, e->weight); + } else { + printf(" %2d", e->adjVertex); + } + } + printf("\n"); + } + } + printf("---\n"); +} + +void GraphListAdjacents(const Graph* g, unsigned int v) { + printf("---\n"); + + unsigned int* array = GraphGetAdjacentsTo(g, v); + + printf("Vertex %d has %d adjacent vertices -> ", v, array[0]); + + for (unsigned int i = 1; i <= array[0]; i++) { + printf("%d ", array[i]); + } + + printf("\n"); + + free(array); + + printf("---\n"); +} diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Graph.h b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Graph.h new file mode 100644 index 0000000..934448f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Graph.h @@ -0,0 +1,94 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - June 2021, Nov 2023 +// +// Graph - Using a list of adjacency lists representation +// + +#ifndef _GRAPH_ +#define _GRAPH_ + +#include + +typedef struct _GraphHeader Graph; + +Graph* GraphCreate(unsigned int numVertices, int isDigraph, int isWeighted); + +Graph* GraphCreateComplete(unsigned int numVertices, int isDigraph); + +void GraphDestroy(Graph** p); + +Graph* GraphCopy(const Graph* g); + +Graph* GraphFromFile(FILE* f); + +// Graph + +int GraphIsDigraph(const Graph* g); + +int GraphIsComplete(const Graph* g); + +int GraphIsWeighted(const Graph* g); + +unsigned int GraphGetNumVertices(const Graph* g); + +unsigned int GraphGetNumEdges(const Graph* g); + +// +// For a graph +// +double GraphGetAverageDegree(const Graph* g); + +// +// For a graph +// +unsigned int GraphGetMaxDegree(const Graph* g); + +// +// For a digraph +// +unsigned int GraphGetMaxOutDegree(const Graph* g); + +// Vertices + +unsigned int* GraphGetAdjacentsTo(const Graph* g, unsigned int v); + +// Vertices distances +double* GraphGetDistancesToAdjacents(const Graph* g, unsigned int v); + +// +// For a graph +// +unsigned int GraphGetVertexDegree(Graph* g, unsigned int v); + +// +// For a digraph +// +unsigned int GraphGetVertexOutDegree(Graph* g, unsigned int v); + +// +// For a digraph +// +unsigned int GraphGetVertexInDegree(Graph* g, unsigned int v); + +// Edges + +int GraphAddEdge(Graph* g, unsigned int v, unsigned int w); + +int GraphAddWeightedEdge(Graph* g, unsigned int v, unsigned int w, + double weight); + +int GraphRemoveEdge(Graph* g, unsigned int v, unsigned int w); + +// CHECKING + +int GraphCheckInvariants(const Graph* g); + +// DISPLAYING on the console + +void GraphDisplay(const Graph* g); + +void GraphListAdjacents(const Graph* g, unsigned int v); + +#endif // _GRAPH_ diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/GraphDFSRec.c b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/GraphDFSRec.c new file mode 100644 index 0000000..cd53042 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/GraphDFSRec.c @@ -0,0 +1,126 @@ +// +// Joaquim Madeira, AlgC, May 2020 +// João Manuel Rodrigues, AlgC, May 2020 +// +// GraphDFSRec - RECURSIVE Depth-First Search +// + +#include "GraphDFSRec.h" + +#include +#include +#include + +#include "Graph.h" +#include "IntegersStack.h" + +struct _GraphDFSRec { + unsigned int* marked; + int* predecessor; + Graph* graph; + unsigned int startVertex; +}; + +static void _dfs(GraphDFSRec* traversal, unsigned int vertex) { + traversal->marked[vertex] = 1; + + unsigned int* neighbors = GraphGetAdjacentsTo(traversal->graph, vertex); + + for (unsigned int i = 1; i <= neighbors[0]; i++) { + unsigned int w = neighbors[i]; + if (traversal->marked[w] == 0) { + traversal->predecessor[w] = vertex; + _dfs(traversal, w); + } + } + + free(neighbors); +} + +GraphDFSRec* GraphDFSRecExecute(Graph* g, unsigned int startVertex) { + assert(g != NULL); + assert(startVertex < GraphGetNumVertices(g)); + + GraphDFSRec* result = (GraphDFSRec*)malloc(sizeof(struct _GraphDFSRec)); + assert(result != NULL); + + unsigned int numVertices = GraphGetNumVertices(g); + + result->marked = (unsigned int*)calloc(numVertices, sizeof(unsigned int)); + assert(result->marked != NULL); + + result->predecessor = (int*)malloc(numVertices * sizeof(int)); + assert(result->predecessor != NULL); + for (unsigned int i = 0; i < numVertices; i++) { + result->predecessor[i] = -1; + } + + result->predecessor[startVertex] = 0; + + result->graph = g; + result->startVertex = startVertex; + + // START THE RECURSIVE TRAVERSAL + + _dfs(result, startVertex); + + return result; +} + +void GraphDFSRecDestroy(GraphDFSRec** p) { + assert(*p != NULL); + + GraphDFSRec* aux = *p; + + free(aux->marked); + free(aux->predecessor); + + free(*p); + *p = NULL; +} + +// Getting the result + +unsigned int GraphDFSRecHasPathTo(const GraphDFSRec* p, unsigned int v) { + assert(v < GraphGetNumVertices(p->graph)); + + return p->marked[v]; +} + +Stack* GraphDFSRecPathTo(const GraphDFSRec* p, unsigned int v) { + assert(v < GraphGetNumVertices(p->graph)); + + Stack* s = StackCreate(GraphGetNumVertices(p->graph)); + + if (p->marked[v] == 0) { + return s; + } + + // Store the path + for (unsigned int current = v; current != p->startVertex; + current = p->predecessor[current]) { + StackPush(s, current); + } + + StackPush(s, p->startVertex); + + return s; +} + +// DISPLAYING on the console + +void GraphDFSRecShowPath(const GraphDFSRec* p, unsigned int v) { + assert(v < GraphGetNumVertices(p->graph)); + + Stack* s = GraphDFSRecPathTo(p, v); + + while (StackIsEmpty(s) == 0) { + printf("%d ", StackPop(s)); + } + + StackDestroy(&s); +} + +void GraphDFSRecDisplay(const GraphDFSRec* p) { + // COMPLETAR !! +} diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/GraphDFSRec.h b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/GraphDFSRec.h new file mode 100644 index 0000000..e0249b4 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/GraphDFSRec.h @@ -0,0 +1,32 @@ +// +// Joaquim Madeira, AlgC, May 2020 +// João Manuel Rodrigues, AlgC, May 2020 +// +// GraphDFS - RECURSIVE Depth-First Search +// + +#ifndef _GRAPH_DFS_REC_ +#define _GRAPH_DFS_REC_ + +#include "Graph.h" +#include "IntegersStack.h" + +typedef struct _GraphDFSRec GraphDFSRec; + +GraphDFSRec* GraphDFSRecExecute(Graph* g, unsigned int startVertex); + +void GraphDFSRecDestroy(GraphDFSRec** p); + +// Getting the result + +unsigned int GraphDFSRecHasPathTo(const GraphDFSRec* p, unsigned int v); + +Stack* GraphDFSRecPathTo(const GraphDFSRec* p, unsigned int v); + +// DISPLAYING on the console + +void GraphDFSRecShowPath(const GraphDFSRec* p, unsigned int v); + +void GraphDFSRecDisplay(const GraphDFSRec* p); + +#endif // _GRAPH_DFS_REC_ diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/IntegersStack.c b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/IntegersStack.c new file mode 100644 index 0000000..2200172 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/IntegersStack.c @@ -0,0 +1,65 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// Integers stack (First In Last Out) implementation based on an array +// + +#include "IntegersStack.h" + +#include +#include + +struct _IntStack { + int max_size; // maximum stack size + int cur_size; // current stack size + int* data; // the stack data (stored in an array) +}; + +Stack* StackCreate(int size) { + assert(size >= 1 && size <= 1000000); + Stack* s = (Stack*)malloc(sizeof(Stack)); + if (s == NULL) abort(); + s->max_size = size; + s->cur_size = 0; + s->data = (int*)malloc(size * sizeof(int)); + if (s->data == NULL) { + free(s); + abort(); + } + return s; +} + +void StackDestroy(Stack** p) { + assert(*p != NULL); + Stack* s = *p; + free(s->data); + free(s); + *p = NULL; +} + +void StackClear(Stack* s) { s->cur_size = 0; } + +int StackSize(const Stack* s) { return s->cur_size; } + +int StackIsFull(const Stack* s) { return (s->cur_size == s->max_size); } + +int StackIsEmpty(const Stack* s) { return (s->cur_size == 0); } + +int StackPeek(const Stack* s) { + assert(s->cur_size > 0); + return s->data[s->cur_size - 1]; +} + +void StackPush(Stack* s, int i) { + assert(s->cur_size < s->max_size); + s->data[s->cur_size++] = i; +} + +int StackPop(Stack* s) { + assert(s->cur_size > 0); + return s->data[--(s->cur_size)]; +} diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/IntegersStack.h b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/IntegersStack.h new file mode 100644 index 0000000..e70ad63 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/IntegersStack.h @@ -0,0 +1,34 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// Integers stack (First In Last Out) implementation based on an array +// + +#ifndef _INTEGERS_STACK_ +#define _INTEGERS_STACK_ + +typedef struct _IntStack Stack; + +Stack* StackCreate(int size); + +void StackDestroy(Stack** p); + +void StackClear(Stack* s); + +int StackSize(const Stack* s); + +int StackIsFull(const Stack* s); + +int StackIsEmpty(const Stack* s); + +int StackPeek(const Stack* s); + +void StackPush(Stack* s, int i); + +int StackPop(Stack* s); + +#endif // _INTEGERS_STACK_ diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Makefile b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Makefile new file mode 100644 index 0000000..1e01ffb --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/Makefile @@ -0,0 +1,34 @@ +# To compile all programs, run: +# make +# +# AED, ua, 2023 + +CFLAGS += -g -Wall -Wextra + +TARGETS = example1 example2 + +all: $(TARGETS) + +example1: example1.o Graph.o SortedList.o + +example2: example2.o Graph.o GraphDFSRec.o IntegersStack.o SortedList.o + +# Dependencies of source files (obtained with gcc -MM) + +example1.o: example1.c Graph.h + +example2.o: example2.c Graph.h GraphDFSRec.h + +Graph.o: Graph.c Graph.h SortedList.h + +GraphDFSRec.o: GraphDFSRec.c GraphDFSRec.h IntegersStack.h + +IntegersStack.o: IntegersStack.c IntegersStack.h + +SortedList.o: SortedList.c SortedList.h + +clean: + rm -f *.o + rm -f $(TARGETS) + + diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/SortedList.c b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/SortedList.c new file mode 100644 index 0000000..9d65ca7 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/SortedList.c @@ -0,0 +1,340 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// SORTED LIST implementation based on an linked list +// + +// ***************** COMPLETAR AS FUNCOES !!! ******************* + +#include "SortedList.h" + +#include +#include + +struct _ListNode { + void* item; + struct _ListNode* next; +}; + +struct _SortedList { + int size; // current List size + struct _ListNode* head; // the head of the List + struct _ListNode* tail; // the tail of the List + struct _ListNode* current; // the current node + int currentPos; // the current node index + compFunc compare; +}; + +List* ListCreate(compFunc compF) { + List* l = (List*)malloc(sizeof(List)); + assert(l != NULL); + + l->size = 0; + l->head = NULL; + l->tail = NULL; + l->current = NULL; + l->currentPos = -1; // Default: before the head of the list + l->compare = compF; + return l; +} + +void ListDestroy(List** p) { + assert(*p != NULL); + List* l = *p; + + ListClear(l); + + free(l); + *p = NULL; +} + +void ListClear(List* l) { + assert(l != NULL); + + struct _ListNode* p = l->head; + struct _ListNode* aux; + + while (p != NULL) { + aux = p; + p = aux->next; + free(aux); + } + + l->size = 0; + l->head = NULL; + l->tail = NULL; + l->current = NULL; + l->currentPos = -1; // Default: before the head of the list +} + +unsigned int ListGetSize(const List* l) { + assert(l != NULL); + return l->size; +} + +int ListIsEmpty(const List* l) { + assert(l != NULL); + return (l->size == 0) ? 1 : 0; +} + +// Current node functions + +int ListGetCurrentIndex(const List* l) { + assert(l != NULL); + return l->currentPos; +} + +void* ListGetCurrentItem(const List* l) { + assert(l != NULL && l->current != NULL); + return l->current->item; +} + +void ListModifyCurrentValue(const List* l, void* p) { + assert(l != NULL && l->current != NULL); + l->current->item = p; +} + +// The move and search functions return 0 on success and -1 on failure (on +// success the current node is changed, on failure it is not changed) + +// Search +// +// starting at the current node, search for the first node with a value of *p +// on failure the current node is not changed +// +int ListSearch(List* l, const void* p) { + int i = (l->currentPos < 0) ? 0 : l->currentPos; + + struct _ListNode* sn = (l->currentPos < 0) ? l->head : l->current; + + while (i < l->size && l->compare(p, sn->item) > 0) { + i++; + sn = sn->next; + } + + if (i == l->size) { + return -1; + } // failure + + if (l->compare(p, sn->item) < 0) { + return -1; + } // failure + + l->current = sn; + l->currentPos = i; + + return 0; // success +} + +// Move to functions + +int ListMove(List* l, int newPos) { + if (newPos < -1 || newPos > l->size) { + return -1; + } // failure + + if (newPos == -1 || newPos == l->size) { + l->current = NULL; + } else if (newPos == 0) { + l->current = l->head; + } else if (newPos == l->size - 1) { + l->current = l->tail; + } else { + if (l->currentPos == -1 || l->currentPos == l->size || + newPos < l->currentPos) { + l->current = l->head; + l->currentPos = 0; + } + + for (int i = l->currentPos; i < newPos; i++) { + l->current = l->current->next; + } + } + l->currentPos = newPos; + + return 0; // success +} + +int ListMoveToNext(List* l) { return ListMove(l, l->currentPos + 1); } + +int ListMoveToPrevious(List* l) { return ListMove(l, l->currentPos - 1); } + +int ListMoveToHead(List* l) { return ListMove(l, 0); } + +int ListMoveToTail(List* l) { return ListMove(l, l->size - 1); } + +// Insert function + +// +// insert a node +// the current node is not changed +// return 0 on success +// return -1 on failure +// +int ListInsert(List* l, void* p) { + struct _ListNode* sn = (struct _ListNode*)malloc(sizeof(struct _ListNode)); + assert(sn != NULL); + sn->item = p; + sn->next = NULL; + + // Empty list + if (l->size == 0) { + l->head = l->tail = sn; + l->size = 1; + return 0; + } + + // Search + + int i = 0; + struct _ListNode* prev = NULL; + struct _ListNode* aux = l->head; + + while (i < l->size && l->compare(p, aux->item) > 0) { + i++; + prev = aux; + aux = aux->next; + } + + if (i == l->size) { // Append at the tail + l->tail->next = sn; + l->tail = sn; + l->size++; + return 0; + } + + if (l->compare(p, aux->item) == 0) { // Already exists !! + free(sn); + return -1; + } // failure + + if (i == 0) { // Append at the head + sn->next = l->head; + l->head = sn; + l->size++; + if (l->currentPos >= 0) { + l->currentPos++; + } + return 0; + } + + sn->next = aux; + prev->next = sn; + l->size++; + if (l->currentPos >= i) { + l->currentPos++; + } + + return 0; +} + +// Remove functions + +// +// remove the head of the list and make its next node the new head +// if the current node is the head, it is replaced by its next node +// +void* ListRemoveHead(List* l) { + assert(l->size > 0); + if (l->current == l->head) { + l->current = l->head->next; + l->currentPos++; + } + if (l->size == 1) { + void* p = l->head->item; + free(l->head); + l->head = NULL; + l->tail = NULL; + l->size = 0; + if (l->currentPos > 0) l->currentPos = 0; + return p; + } else { + struct _ListNode* sn = l->head->next; + void* p = l->head->item; + free(l->head); + l->head = sn; + if (l->currentPos > 0) l->currentPos--; + l->size--; + return p; + } +} + +// +// remove the tail of the list and make its previous node the new tail +// if the current node is the tail, it is replaced by it by its next node +// +void* ListRemoveTail(List* l) { + assert(l->size > 0); + if (l->current == l->tail) { + l->current = NULL; + l->currentPos++; + } + if (l->size == 1) { + void* p = l->head->item; + free(l->head); + l->head = NULL; + l->tail = NULL; + l->current = NULL; + if (l->currentPos > 0) l->currentPos = 0; + l->size = 0; + return p; + } else { + struct _ListNode* sn = l->head; + while (sn->next != l->tail) sn = sn->next; + sn->next = NULL; + void* p = l->tail->item; + free(l->tail); + l->tail = sn; + if (l->currentPos == l->size) l->currentPos--; + l->size--; + return p; + } +} + +// +// remove the current node and make its next node the current node +// +void* ListRemoveCurrent(List* l) { + assert(l->currentPos >= 0 && l->currentPos < l->size); + if (l->currentPos == 0) + return ListRemoveHead(l); + else if (l->currentPos == l->size - 1) + return ListRemoveTail(l); + else { + struct _ListNode* sn = l->head; + while (sn->next != l->current) sn = sn->next; + sn->next = l->current->next; + void* p = l->current->item; + free(l->current); + l->current = sn->next; + l->size--; + return p; + } +} + +// Tests + +void ListTestInvariants(const List* l) { + assert(l->size >= 0); + if (l->size == 0) + assert(l->head == NULL && l->tail == NULL); + else + assert(l->head != NULL && l->tail != NULL); + if (l->size == 1) assert(l->head == l->tail); + assert(-1 <= l->currentPos && l->currentPos <= l->size); + if (l->currentPos == -1 || l->currentPos == l->size) + assert(l->current == NULL); + struct _ListNode* sn = l->head; + for (int i = 0; i < l->size; i++) { + if (i == l->size - 1) + assert(sn == l->tail && sn->next == NULL); + else + assert(sn->next != NULL); + if (i == l->currentPos) assert(sn == l->current); + sn = sn->next; + } +} diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/SortedList.h b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/SortedList.h new file mode 100644 index 0000000..67b77db --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/SortedList.h @@ -0,0 +1,70 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, April 2020, November 2023 +// +// Adapted from Tomás Oliveira e Silva, AED, September 2015 +// +// SORTED LIST implementation based on a linked list +// + +#ifndef _SORTED_LIST_ +#define _SORTED_LIST_ + +typedef struct _SortedList List; +typedef int (*compFunc)(const void* p1, const void* p2); + +List* ListCreate(compFunc compF); + +void ListDestroy(List** p); + +void ListClear(List* l); + +unsigned int ListGetSize(const List* l); + +int ListIsEmpty(const List* l); + +// Current node functions + +int ListGetCurrentIndex(const List* l); + +void* ListGetCurrentItem(const List* l); + +void ListModifyCurrentItem(const List* l, void* p); + +// The move and search functions return 0 on success and -1 on failure (on +// success the current node is changed, on failure it is not changed) + +// Search + +int ListSearch(List* l, const void* p); + +// Move to + +int ListMove(List* l, int newPos); + +int ListMoveToNext(List* l); + +int ListMoveToPrevious(List* l); + +int ListMoveToHead(List* l); + +int ListMoveToTail(List* l); + +// Insert + +int ListInsert(List* l, void* p); + +// Remove + +void* ListRemoveHead(List* l); + +void* ListRemoveTail(List* l); + +void* ListRemoveCurrent(List* l); + +// Tests + +void ListTestInvariants(const List* l); + +#endif // _SORTED_LIST_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/example1.c b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/example1.c new file mode 100644 index 0000000..840713a --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/example1.c @@ -0,0 +1,51 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - June 2021, Nov 2023 +// +// Graph EXAMPLE +// + +#include "Graph.h" + +int main(void) { + // What kind of graph is g01? + Graph* g01 = GraphCreate(6, 0, 0); + GraphAddEdge(g01, 1, 2); + GraphAddEdge(g01, 1, 4); + GraphAddEdge(g01, 3, 4); + printf("The first graph:\n"); + GraphDisplay(g01); + for (int i = 0; i < 6; i++) { + GraphListAdjacents(g01, i); + } + printf("Remove edge (1,2)\n"); + GraphDisplay(g01); + for (int i = 0; i < 6; i++) { + GraphListAdjacents(g01, i); + } + + Graph* dig01 = GraphCreate(6, 1, 0); + GraphAddEdge(dig01, 1, 2); + GraphAddEdge(dig01, 1, 4); + GraphAddEdge(dig01, 3, 4); + printf("The second graph:\n"); + GraphDisplay(dig01); + printf("Remove edge (1,2)\n"); + GraphDisplay(dig01); + + Graph* g03 = GraphCreate(6, 0, 1); + GraphAddWeightedEdge(g03, 1, 2, 3); + GraphAddWeightedEdge(g03, 1, 4, 5); + GraphAddWeightedEdge(g03, 3, 4, 10); + printf("The third graph:\n"); + GraphDisplay(g03); + printf("Remove edge (1,2)\n"); + GraphDisplay(g03); + + GraphDestroy(&g01); + GraphDestroy(&dig01); + GraphDestroy(&g03); + + return 0; +} diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/example2.c b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/example2.c new file mode 100644 index 0000000..8abbbe4 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema10/22_AED_Grafos_II/example2.c @@ -0,0 +1,64 @@ +// +// Algoritmos e Estruturas de Dados --- 2023/2024 +// +// Joaquim Madeira, Joao Manuel Rodrigues - May 2020, Nov 2023 +// +// Graph EXAMPLE +// + +#include "Graph.h" +#include "GraphDFSRec.h" + +int main(void) { + // Graph + Graph* g01 = GraphCreate(6, 0, 0); + + GraphAddEdge(g01, 0, 5); + GraphAddEdge(g01, 2, 4); + GraphAddEdge(g01, 2, 3); + GraphAddEdge(g01, 1, 2); + GraphAddEdge(g01, 0, 1); + GraphAddEdge(g01, 3, 4); + GraphAddEdge(g01, 3, 5); + GraphAddEdge(g01, 0, 2); + + GraphDisplay(g01); + + // DFS traversal starting at vertex 0 + GraphDFSRec* traversal = GraphDFSRecExecute(g01, 0); + + printf("Path from 0 to 5: "); + GraphDFSRecShowPath(traversal, 5); + printf("\n"); + + GraphDFSRecDestroy(&traversal); + + GraphDestroy(&g01); + + // Digraph + g01 = GraphCreate(6, 1, 0); + + GraphAddEdge(g01, 0, 5); + GraphAddEdge(g01, 2, 4); + GraphAddEdge(g01, 2, 3); + GraphAddEdge(g01, 1, 2); + GraphAddEdge(g01, 0, 1); + GraphAddEdge(g01, 3, 4); + GraphAddEdge(g01, 3, 5); + GraphAddEdge(g01, 0, 2); + + GraphDisplay(g01); + + // DFS traversal starting at vertex 1 + traversal = GraphDFSRecExecute(g01, 1); + + printf("Path from 1 to 5: "); + GraphDFSRecShowPath(traversal, 5); + printf("\n"); + + GraphDFSRecDestroy(&traversal); + + GraphDestroy(&g01); + + return 0; +} diff --git a/2ano/1semestre/aed/teoricas/tema10/22_AED__Grafos_II.pdf b/2ano/1semestre/aed/teoricas/tema10/22_AED__Grafos_II.pdf new file mode 100644 index 0000000..6676552 Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema10/22_AED__Grafos_II.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema11/23_AED_Linguagem_C++_I.pdf b/2ano/1semestre/aed/teoricas/tema11/23_AED_Linguagem_C++_I.pdf new file mode 100644 index 0000000..e26f66e Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema11/23_AED_Linguagem_C++_I.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/Fraction.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/Fraction.cpp new file mode 100644 index 0000000..0cfc75f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/Fraction.cpp @@ -0,0 +1,115 @@ +// J. Madeira --- February 2022 + +#include "Fraction.h" + +#include +#include +#include + +Fraction::Fraction(void) : numerator_(0), denominator_(1) {} + +Fraction::Fraction(int numerator, int denominator) { + assert(denominator > 0); + numerator_ = numerator; + denominator_ = denominator; + Reduce(); +} + +int Fraction::GetNumerator(void) const { return numerator_; } +void Fraction::SetNumerator(int n) { + numerator_ = n; + Reduce(); +} + +int Fraction ::GetDenominator(void) const { return denominator_; } +void Fraction::SetDenominator(int n) { + assert(n > 0); + denominator_ = n; + Reduce(); +} + +// Comparison operators + +bool Fraction::operator==(const Fraction& frac) const { + return (numerator_ == frac.numerator_) && (denominator_ == frac.denominator_); +} + +bool Fraction::operator!=(const Fraction& frac) const { + return !(*this == frac); +} + +bool Fraction::operator<(const Fraction& frac) const { + // Not the smartest way + return ToDouble() < frac.ToDouble(); +} + +// Unary operator + +Fraction Fraction::operator-(void) const { + Fraction res(-numerator_, denominator_); + return res; +} + +// Binary operators +Fraction Fraction::operator+(const Fraction& frac) const { + Fraction res(*this); + if (res.denominator_ == frac.denominator_) { + res.numerator_ += frac.numerator_; + } else { + res.numerator_ = + res.numerator_ * frac.denominator_ + frac.numerator_ * res.denominator_; + res.denominator_ *= frac.denominator_; + } + res.Reduce(); + return res; +} + +Fraction Fraction::operator-(const Fraction& frac) const { + return *this + (-frac); +} + +Fraction Fraction::operator*(const Fraction& frac) const { + Fraction res(*this); + + res.numerator_ *= frac.numerator_; + res.denominator_ *= frac.denominator_; + + res.Reduce(); + return res; +} + +Fraction Fraction::operator/(const Fraction& frac) const { + assert(frac.numerator_ != 0); + + Fraction res(*this); + + res.numerator_ *= frac.denominator_; + res.denominator_ *= frac.numerator_; + + // Ensure the denominator is POSITIVE + if (res.denominator_ < 0) { + res.numerator_ *= -1; + res.denominator_ *= -1; + } + + res.Reduce(); + return res; +} + +double Fraction::ToDouble(void) const { + return (double)numerator_ / (double)denominator_; +} + +std::ostream& operator<<(std::ostream& os, const Fraction& frac) { + os << frac.numerator_ << " / " << frac.denominator_; + return os; +} + +void Fraction::Reduce(void) { + int gcd = std::gcd(numerator_, denominator_); // Since C++17 + + if (gcd != 1) { + numerator_ /= gcd; + denominator_ /= gcd; + } +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/Fraction.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/Fraction.h new file mode 100644 index 0000000..1cebe26 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/Fraction.h @@ -0,0 +1,44 @@ +// J. Madeira --- March 2023 + +#ifndef FRACTION_H_ +#define FRACTION_H_ + +#include + +class Fraction { + public: + Fraction(void); + Fraction(int numerator, int denominator = 1); + + int GetNumerator(void) const; + void SetNumerator(int n); + + int GetDenominator(void) const; + void SetDenominator(int n); + + // Comparison operators + bool operator==(const Fraction& frac) const; + bool operator!=(const Fraction& frac) const; + bool operator<(const Fraction& frac) const; + + // Unary operator + Fraction operator-(void) const; + + // Binary operators + Fraction operator+(const Fraction& frac) const; + Fraction operator-(const Fraction& frac) const; + Fraction operator*(const Fraction& frac) const; + Fraction operator/(const Fraction& frac) const; + + double ToDouble(void) const; + + friend std::ostream& operator<<(std::ostream& out, const Fraction& frac); + + private: + void Reduce(void); + + int numerator_; + int denominator_; // ALWAYS POSITIVE !!! +}; + +#endif // FRACTION_H_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/README.txt b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/README.txt new file mode 100644 index 0000000..663cd3f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/README.txt @@ -0,0 +1,4 @@ + +Compile with + +g++ TestFraction.cpp Fraction.cpp -Wall -Wextra -std=c++17 \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/TestFraction.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/TestFraction.cpp new file mode 100644 index 0000000..d9026db --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/01_Fraction_Class/TestFraction.cpp @@ -0,0 +1,52 @@ +// J. Madeira --- February 2022 + +#include + +#include "Fraction.h" + +int main(void) { + Fraction zero; // Has value ZERO + Fraction fraction_1; + Fraction fraction_2(5); + Fraction fraction_3(2, 4); + + std::cout << "1st fraction: " << fraction_1 << " = " << fraction_1.ToDouble() + << std::endl; + + std::cout << "2nd fraction: " << fraction_2 << " = " << fraction_2.ToDouble() + << std::endl; + + std::cout << "3rd fraction: " << fraction_3 << " = " << fraction_3.ToDouble() + << std::endl; + + std::cout << fraction_1 << " is equal to " << fraction_3; + std::cout << " : " << std::boolalpha << (fraction_2 == fraction_3) + << std::endl; + + std::cout << fraction_2 << " is different from " << fraction_3; + std::cout << " : " << std::boolalpha << (fraction_2 != fraction_3) + << std::endl; + + // For this simple class, the assignment operator works + fraction_1 = fraction_2; + + std::cout << fraction_1 << " is equal to " << fraction_2; + std::cout << " : " << std::boolalpha << (fraction_1 == fraction_2) + << std::endl; + + // Arithmetic operations + + std::cout << fraction_2 << " + " << fraction_3; + std::cout << " = " << fraction_2 + fraction_3 << std::endl; + + std::cout << fraction_1 << " - " << fraction_2; + std::cout << " = " << fraction_1 - fraction_2 << std::endl; + + std::cout << fraction_1 << " * " << fraction_2; + std::cout << " = " << fraction_1 * fraction_2 << std::endl; + + std::cout << fraction_2 << " / " << fraction_3; + std::cout << " = " << fraction_2 / fraction_3 << std::endl; + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/Counter.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/Counter.cpp new file mode 100644 index 0000000..d0c7803 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/Counter.cpp @@ -0,0 +1,64 @@ +// J. Madeira --- March 2023 + +#include "Counter.h" + +#include +#include +#include + +Counter::Counter(unsigned initial_value) { value_ = initial_value; } + +unsigned Counter::GetValue(void) const { return value_; } + +void Counter::Inc(void) { + if (value_ < std::numeric_limits::max()) { + value_++; + } +} + +void Counter::Dec(void) { + if (value_ > 0) { + value_--; + } +} + +// Comparison operators + +bool Counter::operator==(const Counter& c) const { + return (value_ == c.value_); +} + +bool Counter::operator!=(const Counter& c) const { return !(*this == c); } + +bool Counter::operator<(const Counter& c) const { return value_ < c.value_; } + +// Postfix operators +// Extra parameter to allow for prefix and postfix notations + +Counter Counter::operator++(int) { + Counter old_counter = *this; + Inc(); + return old_counter; +} + +Counter Counter::operator--(int) { + Counter old_counter = *this; + Dec(); + return old_counter; +} + +// Prefix operators +Counter& Counter::operator++(void) { + Inc(); + return *this; +} + +Counter& Counter::operator--(void) { + Dec(); + return *this; +} + +std::ostream& operator<<(std::ostream& os, const Counter& c) { + os << c.value_; + return os; +} diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/Counter.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/Counter.h new file mode 100644 index 0000000..5ca0df1 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/Counter.h @@ -0,0 +1,37 @@ +// J. Madeira --- March 2023 + +#ifndef COUNTER_H_ +#define COUNTER_H_ + +#include + +class Counter { + public: + Counter(unsigned initial_value = 0); + + unsigned GetValue(void) const; + + void Inc(void); + void Dec(void); + + // Comparison operators + bool operator==(const Counter& c) const; + bool operator!=(const Counter& c) const; + bool operator<(const Counter& c) const; + + // Postfix operators + // Extra parameter to allow for prefix and postfix notations + Counter operator++(int); + Counter operator--(int); + + // Prefix operators + Counter& operator++(void); + Counter& operator--(void); + + friend std::ostream& operator<<(std::ostream& out, const Counter& c); + + protected: + unsigned value_; +}; + +#endif // COUNTER_H_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/LimitedCounter.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/LimitedCounter.cpp new file mode 100644 index 0000000..2a3794a --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/LimitedCounter.cpp @@ -0,0 +1,40 @@ +// J. Madeira --- March 2023 + +#include "LimitedCounter.h" + +#include +#include +#include + +#include "Counter.h" + +LimitedCounter::LimitedCounter(unsigned max_value, unsigned initial_value) + : Counter(initial_value) { + max_value_ = max_value; +} + +void LimitedCounter::Inc(void) { + if (value_ < max_value_) { + value_++; + } +} + +// Postfix operators +// Extra parameter to allow for prefix and postfix notations + +LimitedCounter LimitedCounter::operator++(int) { + LimitedCounter old_LimitedCounter = *this; + Inc(); + return old_LimitedCounter; +} + +// Prefix operators +LimitedCounter& LimitedCounter::operator++(void) { + Inc(); + return *this; +} + +std::ostream& operator<<(std::ostream& os, const LimitedCounter& c) { + os << c.value_; + return os; +} diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/LimitedCounter.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/LimitedCounter.h new file mode 100644 index 0000000..2d30a46 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/LimitedCounter.h @@ -0,0 +1,33 @@ +// J. Madeira --- March 2023 + +#ifndef LIMITED_COUNTER_H_ +#define LIMITED_COUNTER_H_ + +#include + +#include "Counter.h" + +class LimitedCounter : public Counter { + public: + LimitedCounter(unsigned max_value, unsigned initial_value = 0); + + void Inc(void); + + // Postfix operator + // Extra parameter to allow for prefix and postfix notations + LimitedCounter operator++(int); + + // operator-- is inherited!! + + // Prefix operator + LimitedCounter& operator++(void); + + // operator-- is inherited!! + + friend std::ostream& operator<<(std::ostream& out, const LimitedCounter& c); + + private: + unsigned max_value_; +}; + +#endif // LIMITED_COUNTER_H_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/README.txt b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/README.txt new file mode 100644 index 0000000..b7d02b7 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/README.txt @@ -0,0 +1,3 @@ + +The value_ attibute of the base class is now protected -> Efficiency! + diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/TestCounters.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/TestCounters.cpp new file mode 100644 index 0000000..6910013 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/02_Inheritance_Counters/TestCounters.cpp @@ -0,0 +1,93 @@ +// J. Madeira --- March 2023 + +#include + +#include "Counter.h" +#include "LimitedCounter.h" + +int main(void) { + std::cout << "COUNTERS" << std::endl; + + Counter counter_1; + Counter counter_2(5); + Counter counter_3(4); + + std::cout << "1st counter: " << counter_1 << std::endl; + + std::cout << "2nd counter: " << counter_2 << std::endl; + + std::cout << "3rd counter: " << counter_3 << std::endl; + + std::cout << counter_1 << " is equal to " << counter_3; + std::cout << " : " << std::boolalpha << (counter_1 == counter_3) << std::endl; + + std::cout << counter_2 << " is different from " << counter_3; + std::cout << " : " << std::boolalpha << (counter_2 != counter_3) << std::endl; + + std::cout << counter_2 << " is smaller than " << counter_3; + std::cout << " : " << std::boolalpha << (counter_2 < counter_3) << std::endl; + + // For this simple class, the assignment operator works + counter_1 = counter_2; + + std::cout << counter_1 << " is equal to " << counter_2; + std::cout << " : " << std::boolalpha << (counter_1 == counter_2) << std::endl; + + // Increment / Decrement operations + + std::cout << "1st counter: " << counter_1 << std::endl; + + ++counter_1; + + std::cout << "After ++counter_1: " << counter_1 << std::endl; + + counter_1++; + + std::cout << "After counter_1++: " << counter_1 << std::endl; + + Counter aux; + + std::cout << "aux counter: " << aux << std::endl; + + --counter_1; + + std::cout << "After --aux: " << aux << std::endl; + + std::cout << "LIMITED COUNTERS" << std::endl; + + LimitedCounter c_1(10); + LimitedCounter c_2(5); + + std::cout << "1st counter: " << c_1 << std::endl; + + std::cout << "2nd counter: " << c_2 << std::endl; + + for (int i = 0; i < 12; i++) { + c_1++; + ++c_2; + } + + std::cout << "1st counter: " << c_1 << std::endl; + + std::cout << "2nd counter: " << c_2 << std::endl; + + std::cout << c_1 << " is equal to " << c_2; + std::cout << " : " << std::boolalpha << (c_1 == c_2) << std::endl; + + std::cout << c_2 << " is different from " << c_1; + std::cout << " : " << std::boolalpha << (c_2 != c_1) << std::endl; + + std::cout << c_2 << " is smaller than " << c_1; + std::cout << " : " << std::boolalpha << (c_2 < c_1) << std::endl; + + for (int i = 0; i < 12; i++) { + --c_1; + c_2--; + } + + std::cout << "1st counter: " << c_1 << std::endl; + + std::cout << "2nd counter: " << c_2 << std::endl; + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Animals.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Animals.cpp new file mode 100644 index 0000000..4151d5d --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Animals.cpp @@ -0,0 +1,33 @@ +// Exercise 14-1 Animals.cpp +// Implementations of the Animal class and classes derived from Animal + +#include "Animals.h" + +// Constructor +Animal::Animal(std::string_view theName, unsigned wt) + : name(theName), weight(wt) +{} + +// Return string describing the animal +std::string Animal::who() const +{ + return "My name is " + name + ". My weight is " + std::to_string(weight) + " lbs."; +} + +// Make like a sheep +std::string_view Sheep::sound() const +{ + return "Baaaa!!"; +} + +// Make like a dog +std::string_view Dog::sound() const +{ + return "Woof woof!!"; +} + +// Make like a cow +std::string_view Cow::sound() const +{ + return "Mooooo!!"; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Animals.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Animals.h new file mode 100644 index 0000000..72a7f74 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Animals.h @@ -0,0 +1,43 @@ +// Exercise 14-1 Animals.h +// Animal classes +#ifndef ANIMALS_H +#define ANIMALS_H + +#include +#include + +class Animal +{ +private: + std::string name; // Name of the animal + unsigned weight; // Weight of the animal + +public: + Animal(std::string_view theName, unsigned wt); // Constructor + virtual ~Animal() = default; // Very important: a virtual destructor! + virtual std::string who() const; // Return string containing name and weight + virtual std::string_view sound() const = 0; // Return the sound of an animal +}; + +class Sheep : public Animal +{ +public: + using Animal::Animal; // Inherit constructor + std::string_view sound() const override; // Return the sound of a sheep +}; + +class Dog : public Animal +{ +public: + using Animal::Animal; // Inherit constructor + std::string_view sound() const override; // Return the sound of a dog +}; + +class Cow : public Animal +{ +public: + using Animal::Animal; // Inherit constructor + std::string_view sound() const override; // Return the sound of a cow +}; + +#endif \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/README.txt b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/README.txt new file mode 100644 index 0000000..7aa1b4a --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/README.txt @@ -0,0 +1,39 @@ + +-> Compile with -std=c++17, if needed. + +-> std::string_view + +Conceptually, string_view is only a view of the string and cannot​ be used to modify the actual string. + +When a string_view is created, there's no need to copy the data (unlike when you create a copy of a string). + +Furthermore, in terms of size on the heap, string_view is smaller than std::string + +-> virtual function specifier + +Virtual functions are member functions whose behavior can be overridden in derived classes. + +As opposed to non-virtual functions, the overriding behavior is preserved even if there is no compile-time information about the actual type of the class. + +That is to say, if a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class. + +Such a function call is known as virtual function call or virtual call. + +Virtual function call is suppressed if the function is selected using qualified name lookup (that is, if the function's name appears to the right of the scope resolution operator ::). + +-> std::shared_ptr + +Defined in header + +A smart pointer that retains shared ownership of an object through a pointer. + +Several shared_ptr objects may own the same object. + +The object is destroyed and its memory deallocated when either of the following happens: +- the last remaining shared_ptr owning the object is destroyed; +- the last remaining shared_ptr owning the object is assigned another pointer via operator= or reset(). + +-> final specifier + +Specifies that a virtual function cannot be overridden in a derived class or that a class cannot be derived from. + diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Soln14_01.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Soln14_01.cpp new file mode 100644 index 0000000..c85b03c --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Soln14_01.cpp @@ -0,0 +1,63 @@ +// Exercise 14-1 Exercising Zoo and Animal classes +#include // For basic random number generation (std::rand() and srand()) +#include // For std::time() (used to seed the pseudo-random number generator) +#include + +#include "Zoo.h" + +// Function to generate a random integer 0 to count-1 +unsigned random(size_t count) { + return static_cast(rand() / (RAND_MAX / count + 1)); +} + +int main() { + std::srand( + static_cast(std::time(0))); // Seed random number generator + + const std::vector dogNames{ + "Fido", "Rover", "Lassie", "Lambikins", "Poochy", + "Spit", "Gnasher", "Samuel", "Wellington", "Patch"}; + const std::vector sheepNames{ + "Bozo", "Killer", "Tasty", "Pete", "Chops", + "Blackie", "Whitey", "Eric", "Sean", "Shep"}; + const std::vector cowNames{"Dolly", "Daisy", "Shakey", "Amy", + "Dilly", "Dizzy", "Eleanor", "Zippy", + "Zappy", "Happy"}; + + const unsigned minDogWt{1}; // Minimum weight of a dog in pounds + const unsigned maxDogWt{120}; // Maximum weight of a dog in pounds + const unsigned minSheepWt{80}; // Minimum weight of a dog in pounds + const unsigned maxSheepWt{150}; // Maximum weight of a dog in pounds + const unsigned minCowWt{800}; // Minimum weight of a dog in pounds + const unsigned maxCowWt{1500}; // Maximum weight of a dog in pounds + + std::vector animals; // Stores smart pointers to animals + size_t nAnimals{}; // Number of animals to be created + std::cout << "How many animals in the zoo? "; + std::cin >> nAnimals; + + Zoo zoo; // Create an empty Zoo + + // Create random animals and add them to the Zoo + for (size_t i{}; i < nAnimals; ++i) { + switch (random(3)) { + case 0: // Create a sheep + zoo.addAnimal(std::make_shared( + sheepNames[random(sheepNames.size())], + minSheepWt + random(maxSheepWt - minSheepWt + 1))); + break; + case 1: // Create a dog + zoo.addAnimal( + std::make_shared(dogNames[random(dogNames.size())], + minDogWt + random(maxDogWt - minDogWt + 1))); + break; + case 2: // Create a cow + zoo.addAnimal( + std::make_shared(cowNames[random(cowNames.size())], + minCowWt + random(maxCowWt - minCowWt + 1))); + break; + } + } + + zoo.showAnimals(); // Display the animals +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Zoo.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Zoo.cpp new file mode 100644 index 0000000..3460dbe --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Zoo.cpp @@ -0,0 +1,23 @@ +// Exercise 14-1 Zoo.cpp +// Implementations of the Zoo class that stores pointers to Animals +#include "Zoo.h" +#include "Animals.h" +#include + +// Constructor from a vector of animals +Zoo::Zoo(const std::vector& new_animals) : animals {new_animals} {} + +// Add an animal to the zoo +void Zoo::addAnimal(AnimalPtr animal) +{ + animals.push_back(animal); +} + +// Output the animals and the sound they make +void Zoo::showAnimals() const +{ + for (auto animal : animals) + { + std::cout << animal->who() << ' ' << animal->sound() << std::endl; + } +} diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Zoo.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Zoo.h new file mode 100644 index 0000000..bf511bb --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/03_Horton_Polymorphism_Ex_14_01_Animals/Zoo.h @@ -0,0 +1,26 @@ +// Exercise 14-1 Animals.h +// The Zoo class representing a collection of animals +#ifndef ZOO_H +#define ZOO_H + +#include "Animals.h" +#include +#include + +using AnimalPtr = std::shared_ptr; // Define a type alias for convenience + +class Zoo +{ +private: + std::vector animals; // Stores pointers to the animals + +public: + Zoo() = default; // Default constructor for an empty zoo + Zoo(const std::vector& new_animals); // Constructor from a vector of animals + virtual ~Zoo() = default; // Add a virtual destructr to allow classes to safely derive from Zoo; + // possible examples of Zoo specializations include SafariPark, PettingZoo, ... + void addAnimal(AnimalPtr animal); // Add an animal to the zoo + void showAnimals() const; // Output the animals and the sound they make +}; + +#endif \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Fraction.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Fraction.cpp new file mode 100644 index 0000000..0cfc75f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Fraction.cpp @@ -0,0 +1,115 @@ +// J. Madeira --- February 2022 + +#include "Fraction.h" + +#include +#include +#include + +Fraction::Fraction(void) : numerator_(0), denominator_(1) {} + +Fraction::Fraction(int numerator, int denominator) { + assert(denominator > 0); + numerator_ = numerator; + denominator_ = denominator; + Reduce(); +} + +int Fraction::GetNumerator(void) const { return numerator_; } +void Fraction::SetNumerator(int n) { + numerator_ = n; + Reduce(); +} + +int Fraction ::GetDenominator(void) const { return denominator_; } +void Fraction::SetDenominator(int n) { + assert(n > 0); + denominator_ = n; + Reduce(); +} + +// Comparison operators + +bool Fraction::operator==(const Fraction& frac) const { + return (numerator_ == frac.numerator_) && (denominator_ == frac.denominator_); +} + +bool Fraction::operator!=(const Fraction& frac) const { + return !(*this == frac); +} + +bool Fraction::operator<(const Fraction& frac) const { + // Not the smartest way + return ToDouble() < frac.ToDouble(); +} + +// Unary operator + +Fraction Fraction::operator-(void) const { + Fraction res(-numerator_, denominator_); + return res; +} + +// Binary operators +Fraction Fraction::operator+(const Fraction& frac) const { + Fraction res(*this); + if (res.denominator_ == frac.denominator_) { + res.numerator_ += frac.numerator_; + } else { + res.numerator_ = + res.numerator_ * frac.denominator_ + frac.numerator_ * res.denominator_; + res.denominator_ *= frac.denominator_; + } + res.Reduce(); + return res; +} + +Fraction Fraction::operator-(const Fraction& frac) const { + return *this + (-frac); +} + +Fraction Fraction::operator*(const Fraction& frac) const { + Fraction res(*this); + + res.numerator_ *= frac.numerator_; + res.denominator_ *= frac.denominator_; + + res.Reduce(); + return res; +} + +Fraction Fraction::operator/(const Fraction& frac) const { + assert(frac.numerator_ != 0); + + Fraction res(*this); + + res.numerator_ *= frac.denominator_; + res.denominator_ *= frac.numerator_; + + // Ensure the denominator is POSITIVE + if (res.denominator_ < 0) { + res.numerator_ *= -1; + res.denominator_ *= -1; + } + + res.Reduce(); + return res; +} + +double Fraction::ToDouble(void) const { + return (double)numerator_ / (double)denominator_; +} + +std::ostream& operator<<(std::ostream& os, const Fraction& frac) { + os << frac.numerator_ << " / " << frac.denominator_; + return os; +} + +void Fraction::Reduce(void) { + int gcd = std::gcd(numerator_, denominator_); // Since C++17 + + if (gcd != 1) { + numerator_ /= gcd; + denominator_ /= gcd; + } +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Fraction.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Fraction.h new file mode 100644 index 0000000..1cebe26 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Fraction.h @@ -0,0 +1,44 @@ +// J. Madeira --- March 2023 + +#ifndef FRACTION_H_ +#define FRACTION_H_ + +#include + +class Fraction { + public: + Fraction(void); + Fraction(int numerator, int denominator = 1); + + int GetNumerator(void) const; + void SetNumerator(int n); + + int GetDenominator(void) const; + void SetDenominator(int n); + + // Comparison operators + bool operator==(const Fraction& frac) const; + bool operator!=(const Fraction& frac) const; + bool operator<(const Fraction& frac) const; + + // Unary operator + Fraction operator-(void) const; + + // Binary operators + Fraction operator+(const Fraction& frac) const; + Fraction operator-(const Fraction& frac) const; + Fraction operator*(const Fraction& frac) const; + Fraction operator/(const Fraction& frac) const; + + double ToDouble(void) const; + + friend std::ostream& operator<<(std::ostream& out, const Fraction& frac); + + private: + void Reduce(void); + + int numerator_; + int denominator_; // ALWAYS POSITIVE !!! +}; + +#endif // FRACTION_H_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Pair.h b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Pair.h new file mode 100644 index 0000000..823d5e5 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/Pair.h @@ -0,0 +1,48 @@ +// Pair.h + +// Just one generic type --- Adapted form Horton's example --- J. Madeira + +#ifndef PAIR_H +#define PAIR_H + +#include + +template +class Pair { + public: // To simplify the example + T first_; + T second_; + + Pair(); + Pair(const T& f, const T& s); + + bool operator==(const Pair& other) const; + bool operator<(const Pair& other) const; +}; + +// Default constructor +template +Pair::Pair() : first_{}, second_{} {} + +// Constructor +template +Pair::Pair(const T& f, const T& s) : first_{f}, second_{s} {} + +// Comparison operators +template +bool Pair::operator==(const Pair& other) const { + return first_ == other.first_ && second_ == other.second_; +} + +template +bool Pair::operator<(const Pair& other) const { + return first_ < other.first_ || + (first_ == other.first_ && second_ < other.second_); +} + +template +std::ostream& operator<<(std::ostream& stream, const Pair& pair) { + return stream << '(' << pair.first_ << ", " << pair.second_ << ')'; +} + +#endif \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/README.txt b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/README.txt new file mode 100644 index 0000000..cdb2d65 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/README.txt @@ -0,0 +1,4 @@ + +If needed, compile with + +g++ -Wall -Wextra -std=c++17 main.cpp Fraction.cpp \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/main.cpp b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/main.cpp new file mode 100644 index 0000000..77efe09 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/24_AED_Examples_for_Students/04_Pair_Template_Class/main.cpp @@ -0,0 +1,72 @@ +// Adapted from Horton's example + +#include +#include + +#include "Fraction.h" +#include "Pair.h" + +int main(void) { + Pair pair_1 = Pair(123, 456); + std::cout << "1st pair is " << pair_1 << std::endl; + + Pair pair_2 = Pair(654, 321); + std::cout << "2nd pair is " << pair_2 << std::endl; + + Pair pair_3 = Pair(654, 322); + std::cout << "3rd pair is " << pair_3 << std::endl; + + std::cout << (pair_1 < pair_2 && pair_2 < pair_3 + ? "operator< seems to be working" + : "oops") + << std::endl; + + std::cout << (pair_1 == pair_2 ? "oops" : "operator== works as well") + << std::endl; + + std::cout << (pair_2 == pair_3 ? "oops" : "operator== works as well") + << std::endl; + + Pair pair_4 = Pair("Joaquim", "Madeira"); + std::cout << "4th pair is " << pair_4 << std::endl; + + Pair pair_5 = Pair("Joao", "Ribeiro"); + std::cout << "5th pair is " << pair_5 << std::endl; + + Pair pair_6 = Pair("Joaquim", "Martins"); + std::cout << "6th pair is " << pair_6 << std::endl; + + std::cout << (pair_5 < pair_4 && pair_4 < pair_6 + ? "operator< seems to be working" + : "oops") + << std::endl; + + std::cout << (pair_4 == pair_5 ? "oops" : "operator== works as well") + << std::endl; + + std::cout << (pair_5 == pair_6 ? "oops" : "operator== works as well") + << std::endl; + + std::cout << "Can also use objects of the Fracion (or any) class..." + << std::endl; + + std::cout << "As long as the required operators are defined" << std::endl; + + Pair pair_7 = Pair(Fraction(1, 2), Fraction(1, 4)); + std::cout << "7th pair is " << pair_7 << std::endl; + + Pair pair_8 = Pair(Fraction(1, 2), Fraction(1, 3)); + std::cout << "8th pair is " << pair_8 << std::endl; + + std::cout << (pair_7 < pair_8 + ? "pair_7 is lexicographically smaller than pair_8" + : "pair_7 is NOT lexicographically smaller than pair_8") + << std::endl; + + std::cout << (pair_8 < pair_7 + ? "pair_8 is lexicographically smaller than pair_7" + : "pair_8 is NOT lexicographically smaller than pair_7") + << std::endl; + + return 0; +} diff --git a/2ano/1semestre/aed/teoricas/tema11/24_AED_Linguagem_C++_II.pdf b/2ano/1semestre/aed/teoricas/tema11/24_AED_Linguagem_C++_II.pdf new file mode 100644 index 0000000..3129b70 Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema11/24_AED_Linguagem_C++_II.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/array_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/array_ex.cpp new file mode 100644 index 0000000..d4eed4e --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/array_ex.cpp @@ -0,0 +1,39 @@ +#include +#include + +using namespace std; + +int main(void) { + array a = {0, 1, 2, 3}; + + // display array size " 4" + cout << " " << a.size() << endl; + + // display contents " 0 1 2 3" + for (const auto& e : a) { + cout << " " << e; + } + cout << endl; + + // display first element " 0" + cout << " " << a.front(); + cout << endl; + + // change first element + a.front() = 9; + + // display last element " 3" + cout << " " << a.back(); + cout << endl; + + // change last element + a.back() = 0; + + // display contents " 9 1 2 0" + for (const auto& e : a) { + cout << " " << e; + } + cout << endl; + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/deque_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/deque_ex.cpp new file mode 100644 index 0000000..f2c7a05 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/deque_ex.cpp @@ -0,0 +1,59 @@ +#include +#include + +using namespace std; + +int main(void) { + deque d = {0, 1, 2, 3}; + + // display deque size " 4" + cout << " " << d.size() << endl; + + // display contents " 0 1 2 3" + for (const auto& e : d) { + cout << " " << e; + } + cout << endl; + + // display first element " 0" + cout << " " << d.front(); + cout << endl; + + // change first element + d.front() = 9; + + // display last element " 3" + cout << " " << d.back(); + cout << endl; + + // change last element + d.back() = 0; + + // display contents " 9 1 2 0" + for (const auto& e : d) { + cout << " " << e; + } + cout << endl; + + // At the front + d.pop_front(); + d.pop_front(); + d.push_front(0); + d.push_front(1); + + // At the back + d.pop_back(); + d.push_back(0); + d.push_back(1); + + // At any position + d.at(2) = 9; + + // display contents + for (const auto& e : d) { + cout << " " << e; + } + cout << endl; + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/map_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/map_ex.cpp new file mode 100644 index 0000000..34f769d --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/map_ex.cpp @@ -0,0 +1,35 @@ +#include +#include + +using namespace std; + +int main(void) { + map m; + + // display map size + cout << " " << m.size() << endl; + + m["February"] = 2; + m["April"] = 4; + m.insert({"May", 5}); + m.insert({"January", 1}); + m.insert({"March", 3}); + m["December"] = 12; + + cout << "key = January value = " << m.at("January") << endl; + cout << "key = February value = " << m["February"] << endl; + + cout << endl; + + for (const auto& e : m) { + cout << "key = " << e.first << " value = " << e.second << endl; + } + + cout << endl; + + for (auto it = m.begin(); it != m.end(); ++it) { + cout << "key = " << (*it).first << " value = " << (*it).second << endl; + } + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/queue_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/queue_ex.cpp new file mode 100644 index 0000000..8108c66 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/queue_ex.cpp @@ -0,0 +1,24 @@ +#include +#include + +using namespace std; + +int main(void) { + queue q; + + // display queue size + cout << " " << q.size() << endl; + + queue uint_queue; + + for (size_t i = 0; i < 10; ++i) { + uint_queue.push(i); + } + + while (!uint_queue.empty()) { + std::cout << uint_queue.front() << std::endl; + uint_queue.pop(); + } + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/set_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/set_ex.cpp new file mode 100644 index 0000000..d16eb21 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/set_ex.cpp @@ -0,0 +1,34 @@ +#include +#include + +using namespace std; + +int main(void) { + set s; + + // display set size + cout << " " << s.size() << endl; + + s.insert("February"); + s.insert("April"); + s.insert("May"); + s.insert("January"); + s.insert("March"); + s.insert("December"); + s.insert("March"); + s.erase("March"); + + cout << endl; + + for (const auto& e : s) { + cout << e << endl; + } + + cout << endl; + + for (auto it = s.begin(); it != s.end(); ++it) { + cout << (*it) << endl; + } + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/stack_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/stack_ex.cpp new file mode 100644 index 0000000..746b8a5 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/stack_ex.cpp @@ -0,0 +1,24 @@ +#include +#include + +using namespace std; + +int main(void) { + stack s; + + // display stack size + cout << " " << s.size() << endl; + + stack uint_stack; + + for (size_t i = 0; i < 10; ++i) { + uint_stack.push(i); + } + + while (!uint_stack.empty()) { + std::cout << uint_stack.top() << std::endl; + uint_stack.pop(); + } + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/vector_ex.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/vector_ex.cpp new file mode 100644 index 0000000..9022697 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/01_VERY_SIMPLE_Examples/vector_ex.cpp @@ -0,0 +1,59 @@ +#include +#include + +using namespace std; + +int main(void) { + vector v = {0, 1, 2, 3}; + + // display vector size " 4" + cout << " " << v.size() << endl; + + // display contents " 0 1 2 3" + for (const auto& e : v) { + cout << " " << e; + } + cout << endl; + + // display first element " 0" + cout << " " << v.front(); + cout << endl; + + // change first element + v.front() = 9; + + // display last element " 3" + cout << " " << v.back(); + cout << endl; + + // change last element + v.back() = 0; + + // display contents " 9 1 2 0" + for (const auto& e : v) { + cout << " " << e; + } + cout << endl; + + // At the front + v.erase(v.begin()); + v.erase(v.begin()); + v.insert(v.begin(), 0); + v.insert(v.begin(), 1); + + // At the back + v.pop_back(); + v.push_back(0); + v.push_back(1); + + // At any position + v.at(2) = 9; + + // display contents + for (const auto& e : v) { + cout << " " << e; + } + cout << endl; + + return (0); +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/02_Queue_Example/queue_example.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/02_Queue_Example/queue_example.cpp new file mode 100644 index 0000000..33078ac --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/02_Queue_Example/queue_example.cpp @@ -0,0 +1,50 @@ +// +// AED --- 2023/2024 +// +// J Madeira, Dec 2023 +// +// Using a queue container to reverse the digits of a positive integer number +// + +#include +#include + +using namespace std; + +int main(void) { + int original_number = 0; + cout << "Write a positive integer value : "; + cin >> original_number; + + if (original_number <= 0) { + cout << "*** Should be a positive integer!! ***" << endl; + return 0; + } + + cout << "The original number : " << original_number << endl; + + // Getting each digit and pushing it into a queue + + queue q; + unsigned int digit; + + while (original_number > 0) { + digit = original_number % 10; + q.push(digit); + original_number /= 10; + } + + // New number with digits in reverse order + + unsigned int new_number = 0; + + while (!q.empty()) { + digit = q.front(); + q.pop(); + new_number = new_number * 10 + digit; + } + + cout << "In reverse order : " << new_number << endl; + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/03_Deque_Example/deque_example.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/03_Deque_Example/deque_example.cpp new file mode 100644 index 0000000..748bdd3 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/03_Deque_Example/deque_example.cpp @@ -0,0 +1,45 @@ +// +// AED --- 2023/2024 +// +// J Madeira, Dec 2023 +// +// Using a deque container to check if a string is a palindrome +// + +#include +#include + +using namespace std; + +int main(void) { + string original_string; + cout << "Write a character string without blank spaces : "; + cin >> original_string; + + // Getting each char and pushing it into the back of a deque + + deque d; + + for (char c : original_string) { + d.push_back(c); + } + + // Is it a palindrome ? + // Read from both ends of the deque + + bool answer = true; + + while (answer && (d.size() > 1)) { + if (d.front() != d.back()) { + answer = false; + } else { + d.pop_front(); + d.pop_back(); + } + } + + cout << "The string \"" << original_string << "\"" + << (answer ? " is " : " is NOT ") << "a palindrome !!" << endl; + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/Fraction.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/Fraction.cpp new file mode 100644 index 0000000..a7e7dd2 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/Fraction.cpp @@ -0,0 +1,114 @@ +// J. Madeira --- February 2022 + +#include "Fraction.h" + +#include +#include +#include + +Fraction::Fraction(void) : numerator_(0), denominator_(1) {} + +Fraction::Fraction(int numerator, int denominator) { + assert(denominator > 0); + numerator_ = numerator; + denominator_ = denominator; + Reduce(); +} + +int Fraction::GetNumerator(void) const { return numerator_; } +void Fraction::SetNumerator(int n) { + numerator_ = n; + Reduce(); +} + +int Fraction ::GetDenominator(void) const { return denominator_; } +void Fraction::SetDenominator(int n) { + assert(n > 0); + denominator_ = n; + Reduce(); +} + +// Comparison operators + +bool Fraction::operator==(const Fraction& frac) const { + return (numerator_ == frac.numerator_) && (denominator_ == frac.denominator_); +} + +bool Fraction::operator!=(const Fraction& frac) const { + return !(*this == frac); +} + +bool Fraction::operator<(const Fraction& frac) const { + return (numerator_ * frac.denominator_) < (frac.numerator_ * denominator_); +} + +// Unary operator + +Fraction Fraction::operator-(void) const { + Fraction res(-numerator_, denominator_); + return res; +} + +// Binary operators +Fraction Fraction::operator+(const Fraction& frac) const { + Fraction res(*this); + if (res.denominator_ == frac.denominator_) { + res.numerator_ += frac.numerator_; + } else { + res.numerator_ = + res.numerator_ * frac.denominator_ + frac.numerator_ * res.denominator_; + res.denominator_ *= frac.denominator_; + } + res.Reduce(); + return res; +} + +Fraction Fraction::operator-(const Fraction& frac) const { + return *this + (-frac); +} + +Fraction Fraction::operator*(const Fraction& frac) const { + Fraction res(*this); + + res.numerator_ *= frac.numerator_; + res.denominator_ *= frac.denominator_; + + res.Reduce(); + return res; +} + +Fraction Fraction::operator/(const Fraction& frac) const { + assert(frac.numerator_ != 0); + + Fraction res(*this); + + res.numerator_ *= frac.denominator_; + res.denominator_ *= frac.numerator_; + + // Ensure the denominator is POSITIVE + if (res.denominator_ < 0) { + res.numerator_ *= -1; + res.denominator_ *= -1; + } + + res.Reduce(); + return res; +} + +double Fraction::ToDouble(void) const { + return (double)numerator_ / (double)denominator_; +} + +std::ostream& operator<<(std::ostream& os, const Fraction& frac) { + os << frac.numerator_ << " / " << frac.denominator_; + return os; +} + +void Fraction::Reduce(void) { + int gcd = std::gcd(numerator_, denominator_); // Since C++17 + + if (gcd != 1) { + numerator_ /= gcd; + denominator_ /= gcd; + } +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/Fraction.h b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/Fraction.h new file mode 100644 index 0000000..1cebe26 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/Fraction.h @@ -0,0 +1,44 @@ +// J. Madeira --- March 2023 + +#ifndef FRACTION_H_ +#define FRACTION_H_ + +#include + +class Fraction { + public: + Fraction(void); + Fraction(int numerator, int denominator = 1); + + int GetNumerator(void) const; + void SetNumerator(int n); + + int GetDenominator(void) const; + void SetDenominator(int n); + + // Comparison operators + bool operator==(const Fraction& frac) const; + bool operator!=(const Fraction& frac) const; + bool operator<(const Fraction& frac) const; + + // Unary operator + Fraction operator-(void) const; + + // Binary operators + Fraction operator+(const Fraction& frac) const; + Fraction operator-(const Fraction& frac) const; + Fraction operator*(const Fraction& frac) const; + Fraction operator/(const Fraction& frac) const; + + double ToDouble(void) const; + + friend std::ostream& operator<<(std::ostream& out, const Fraction& frac); + + private: + void Reduce(void); + + int numerator_; + int denominator_; // ALWAYS POSITIVE !!! +}; + +#endif // FRACTION_H_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/README.txt b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/README.txt new file mode 100644 index 0000000..fc091f2 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/README.txt @@ -0,0 +1,4 @@ + +Compile with + +g++ set_example.cpp Fraction.cpp -Wall -Wextra -std=c++17 \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/set_example.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/set_example.cpp new file mode 100644 index 0000000..994711f --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/04_Set_Example/set_example.cpp @@ -0,0 +1,64 @@ +// +// AED --- 2023/2024 +// +// J Madeira, Dec 2023 +// +// Using a set container to store Fraction objects and count repetitions +// + +#include +#include // For basic random number generation (std::rand() and srand()) +#include // For std::time() (used to seed the pseudo-random number generator) +#include +#include + +#include "Fraction.h" + +using namespace std; + +// Function to generate a random integer 0 to count-1 +unsigned int random(size_t count) { + return static_cast(rand() / (RAND_MAX / count + 1)); +} + +const unsigned int RANGE = 10; + +int main(void) { + std::srand( + static_cast(std::time(0))); // Seed random number generator + + unsigned int n; + cout << "Number of fractions to create : "; + cin >> n; + cout << endl; + + unsigned int repeated_values = 0; + + set fractions_set; + + for (unsigned int i = 0; i < n; ++i) { + Fraction frac = Fraction(1 + random(RANGE), 1 + random(RANGE)); + auto result = fractions_set.insert(frac); + if (result.second == false) { // Tried to insert a repeated fraction value + ++repeated_values; + } + } + + // Checking + assert(n == (fractions_set.size() + repeated_values)); + + cout << "Number of created fractions : " << n << endl; + cout << "Number of repeated values : " << repeated_values << endl; + cout << "Number of different values : " << fractions_set.size() << endl; + + unsigned int aux = 0; + for (const auto& f : fractions_set) { + cout << f << " --- "; + aux++; + if (aux % 6 == 0) { + cout << endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/Fraction.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/Fraction.cpp new file mode 100644 index 0000000..a7e7dd2 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/Fraction.cpp @@ -0,0 +1,114 @@ +// J. Madeira --- February 2022 + +#include "Fraction.h" + +#include +#include +#include + +Fraction::Fraction(void) : numerator_(0), denominator_(1) {} + +Fraction::Fraction(int numerator, int denominator) { + assert(denominator > 0); + numerator_ = numerator; + denominator_ = denominator; + Reduce(); +} + +int Fraction::GetNumerator(void) const { return numerator_; } +void Fraction::SetNumerator(int n) { + numerator_ = n; + Reduce(); +} + +int Fraction ::GetDenominator(void) const { return denominator_; } +void Fraction::SetDenominator(int n) { + assert(n > 0); + denominator_ = n; + Reduce(); +} + +// Comparison operators + +bool Fraction::operator==(const Fraction& frac) const { + return (numerator_ == frac.numerator_) && (denominator_ == frac.denominator_); +} + +bool Fraction::operator!=(const Fraction& frac) const { + return !(*this == frac); +} + +bool Fraction::operator<(const Fraction& frac) const { + return (numerator_ * frac.denominator_) < (frac.numerator_ * denominator_); +} + +// Unary operator + +Fraction Fraction::operator-(void) const { + Fraction res(-numerator_, denominator_); + return res; +} + +// Binary operators +Fraction Fraction::operator+(const Fraction& frac) const { + Fraction res(*this); + if (res.denominator_ == frac.denominator_) { + res.numerator_ += frac.numerator_; + } else { + res.numerator_ = + res.numerator_ * frac.denominator_ + frac.numerator_ * res.denominator_; + res.denominator_ *= frac.denominator_; + } + res.Reduce(); + return res; +} + +Fraction Fraction::operator-(const Fraction& frac) const { + return *this + (-frac); +} + +Fraction Fraction::operator*(const Fraction& frac) const { + Fraction res(*this); + + res.numerator_ *= frac.numerator_; + res.denominator_ *= frac.denominator_; + + res.Reduce(); + return res; +} + +Fraction Fraction::operator/(const Fraction& frac) const { + assert(frac.numerator_ != 0); + + Fraction res(*this); + + res.numerator_ *= frac.denominator_; + res.denominator_ *= frac.numerator_; + + // Ensure the denominator is POSITIVE + if (res.denominator_ < 0) { + res.numerator_ *= -1; + res.denominator_ *= -1; + } + + res.Reduce(); + return res; +} + +double Fraction::ToDouble(void) const { + return (double)numerator_ / (double)denominator_; +} + +std::ostream& operator<<(std::ostream& os, const Fraction& frac) { + os << frac.numerator_ << " / " << frac.denominator_; + return os; +} + +void Fraction::Reduce(void) { + int gcd = std::gcd(numerator_, denominator_); // Since C++17 + + if (gcd != 1) { + numerator_ /= gcd; + denominator_ /= gcd; + } +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/Fraction.h b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/Fraction.h new file mode 100644 index 0000000..1cebe26 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/Fraction.h @@ -0,0 +1,44 @@ +// J. Madeira --- March 2023 + +#ifndef FRACTION_H_ +#define FRACTION_H_ + +#include + +class Fraction { + public: + Fraction(void); + Fraction(int numerator, int denominator = 1); + + int GetNumerator(void) const; + void SetNumerator(int n); + + int GetDenominator(void) const; + void SetDenominator(int n); + + // Comparison operators + bool operator==(const Fraction& frac) const; + bool operator!=(const Fraction& frac) const; + bool operator<(const Fraction& frac) const; + + // Unary operator + Fraction operator-(void) const; + + // Binary operators + Fraction operator+(const Fraction& frac) const; + Fraction operator-(const Fraction& frac) const; + Fraction operator*(const Fraction& frac) const; + Fraction operator/(const Fraction& frac) const; + + double ToDouble(void) const; + + friend std::ostream& operator<<(std::ostream& out, const Fraction& frac); + + private: + void Reduce(void); + + int numerator_; + int denominator_; // ALWAYS POSITIVE !!! +}; + +#endif // FRACTION_H_ \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/README.txt b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/README.txt new file mode 100644 index 0000000..bdcfe96 --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/README.txt @@ -0,0 +1,4 @@ + +Compile with + +g++ map_example.cpp Fraction.cpp -Wall -Wextra -std=c++17 \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/map_example.cpp b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/map_example.cpp new file mode 100644 index 0000000..4988ebc --- /dev/null +++ b/2ano/1semestre/aed/teoricas/tema11/25_AED_Examples_for_Students/05_Map_Example/map_example.cpp @@ -0,0 +1,64 @@ +// +// AED --- 2023/2024 +// +// J Madeira, Dec 2023 +// +// Using a map container to count Fraction object (key) occurrences (value) +// + +#include +#include // For basic random number generation (std::rand() and srand()) +#include // For std::time() (used to seed the pseudo-random number generator) +#include +#include + +#include "Fraction.h" + +using namespace std; + +// Function to generate a random integer 0 to count-1 +unsigned int random(size_t count) { + return static_cast(rand() / (RAND_MAX / count + 1)); +} + +const unsigned int RANGE = 10; + +int main(void) { + std::srand( + static_cast(std::time(0))); // Seed random number generator + + unsigned int n; + cout << "Number of fractions to create : "; + cin >> n; + cout << endl; + + map fraction_counter; + + for (unsigned int i = 0; i < n; ++i) { + Fraction frac = Fraction(1 + random(RANGE), 1 + random(RANGE)); + ++fraction_counter[frac]; // Great way of doing it !! + // If not in the map, insert with value 0 + // and then update + } + + // Checking + unsigned int total_count = 0; + for (const auto& item : fraction_counter) { + total_count += item.second; + } + assert(n == total_count); + + cout << "Number of created fractions : " << n << endl; + cout << "Number of different values : " << fraction_counter.size() << endl; + + unsigned int aux = 0; + for (const auto& item : fraction_counter) { + cout << item.first << " -> " << item.second << " "; + aux++; + if (aux % 6 == 0) { + cout << endl; + } + } + + return 0; +} \ No newline at end of file diff --git a/2ano/1semestre/aed/teoricas/tema11/25_AED_Linguagem_C++_III.pdf b/2ano/1semestre/aed/teoricas/tema11/25_AED_Linguagem_C++_III.pdf new file mode 100644 index 0000000..475659a Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema11/25_AED_Linguagem_C++_III.pdf differ diff --git a/2ano/1semestre/aed/teoricas/tema11/26_AED_Linguagem_C++_IV.pdf b/2ano/1semestre/aed/teoricas/tema11/26_AED_Linguagem_C++_IV.pdf new file mode 100644 index 0000000..4937890 Binary files /dev/null and b/2ano/1semestre/aed/teoricas/tema11/26_AED_Linguagem_C++_IV.pdf differ