[AED] Restructure
Signed-off-by: TiagoRG <tiago.rgarcia@ua.pt>
This commit is contained in:
parent
0df8b9f032
commit
59da5dd695
|
@ -5,6 +5,9 @@
|
|||
# Config files
|
||||
/**/*.iml
|
||||
|
||||
# Data files
|
||||
/**/*.dat
|
||||
|
||||
# Output/Cache files
|
||||
/**/out/
|
||||
/**/__pycache__/
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
|||
# Algoritmos e Estruturas de Dados - Aulas Teóricas
|
||||
### Projetos + resoluções de exercícios organizados por aulas
|
||||
### Linguagem usada: C
|
||||
|
||||
## Índice
|
||||
|
||||
| Tema nº | Tópico |
|
||||
|----------------------------------------------------------------------------------------------|-----------------------------------|
|
||||
| [01](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema01) | Linguagem C |
|
||||
| [02](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema02) | Complexidade de Algoritmos |
|
||||
| [03](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema03) | Algoritmos de Procura e Ordenação |
|
||||
| [04](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema04) | Algoritmos Recursivos |
|
||||
| [05](https://github.com/TiagoRG/uaveiro-leci/tree/master/2ano/1semestre/aed/teoricas/tema05) | Programação Dinâmica |
|
||||
| [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 |
|
||||
|
||||
---
|
||||
*Pode conter erros, caso encontre algum, crie um* [*ticket*](https://github.com/TiagoRG/uaveiro-leci/issues/new)
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#ifndef _POINT2D_H_
|
||||
#define _POINT2D_H_
|
||||
|
||||
typedef struct _Point2D Point2D;
|
||||
|
||||
Point2D* Point2D_CreateXY(double x, double y);
|
||||
Point2D* Point2D_CreatePolar(double radius, double angle_deg);
|
||||
|
||||
void Point2D_Destroy(Point2D** p);
|
||||
|
||||
double Point2D_GetX(const Point2D* p);
|
||||
double Point2D_GetY(const Point2D* p);
|
||||
|
||||
double Point2D_GetRadius(const Point2D* p);
|
||||
double Point2D_GetAngleDegrees(const Point2D* p);
|
||||
|
||||
int Point2D_IsEqual(const Point2D* p1, const Point2D* p2);
|
||||
int Point2D_IsDifferent(const Point2D* p1, const Point2D* p2);
|
||||
|
||||
void Point2D_DisplayXY(const Point2D* p);
|
||||
void Point2D_DisplayPolar(const Point2D* p);
|
||||
|
||||
double Point2D_Distance(const Point2D* p1, const Point2D* p2);
|
||||
|
||||
Point2D* Point2D_MidPoint(const Point2D* p1, const Point2D* p2);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,137 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Point2D.h"
|
||||
|
||||
// Conversion factors
|
||||
#define RAD_TO_DEG 57.2957795
|
||||
#define DEG_TO_RAD 0.0174532925
|
||||
|
||||
// PI
|
||||
#define PI 3.1415926536
|
||||
|
||||
// radius >= 0
|
||||
// angle in range [0, 2 * PI[
|
||||
struct _Point2D {
|
||||
double radius;
|
||||
double angle;
|
||||
};
|
||||
|
||||
Point2D* Point2D_CreateXY(double x, double y) {
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
|
||||
p->radius = sqrt(x * x + y * y);
|
||||
|
||||
if (y == 0.0) {
|
||||
if (x >= 0.0) {
|
||||
p->angle = 0.0;
|
||||
} else {
|
||||
p->angle = PI;
|
||||
}
|
||||
} else if (x == 0.0) {
|
||||
if (y > 0.0) {
|
||||
p->angle = PI / 2.0;
|
||||
} else {
|
||||
p->angle = 3.0 * PI / 4.0;
|
||||
}
|
||||
} else {
|
||||
// In range ]-PI,PI[
|
||||
double angle = atan2(y, x);
|
||||
p->angle = (angle >= 0.0) ? angle : angle + PI;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Point2D* Point2D_CreatePolar(double radius, double angle_deg) {
|
||||
assert(radius >= 0.0);
|
||||
assert((angle_deg >= 0.0) && (angle_deg < 360.0));
|
||||
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
p->radius = radius;
|
||||
p->angle = angle_deg * DEG_TO_RAD;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void Point2D_Destroy(Point2D** p) {
|
||||
assert(*p != NULL);
|
||||
free(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
double Point2D_GetX(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->radius * cos(p->angle);
|
||||
}
|
||||
|
||||
double Point2D_GetY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->radius * sin(p->angle);
|
||||
}
|
||||
|
||||
double Point2D_GetRadius(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
return p->radius;
|
||||
}
|
||||
|
||||
double Point2D_GetAngleDegrees(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
return p->angle * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
int Point2D_IsEqual(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->radius == p2->radius) && (p1->angle == p2->angle);
|
||||
}
|
||||
|
||||
int Point2D_IsDifferent(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->radius != p2->radius) || (p1->angle != p2->angle);
|
||||
}
|
||||
|
||||
void Point2D_DisplayXY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", Point2D_GetX(p), Point2D_GetY(p));
|
||||
}
|
||||
|
||||
void Point2D_DisplayPolar(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", p->radius, p->angle);
|
||||
}
|
||||
|
||||
double Point2D_Distance(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double deltaX = Point2D_GetX(p2) - Point2D_GetX(p1);
|
||||
double deltaY = Point2D_GetY(p2) - Point2D_GetY(p1);
|
||||
|
||||
return sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
}
|
||||
|
||||
Point2D* Point2D_MidPoint(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double new_X = (Point2D_GetX(p1) + Point2D_GetX(p2)) / 2.0;
|
||||
double new_Y = (Point2D_GetY(p1) + Point2D_GetY(p2)) / 2.0;
|
||||
|
||||
Point2D* mid_point = Point2D_CreateXY(new_X, new_Y);
|
||||
|
||||
return mid_point;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Point2D.h"
|
||||
|
||||
// Conversion factors
|
||||
#define RAD_TO_DEG 57.2957795
|
||||
#define DEG_TO_RAD 0.0174532925
|
||||
|
||||
struct _Point2D {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
Point2D* Point2D_CreateXY(double x, double y) {
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
p->x = x;
|
||||
p->y = y;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Point2D* Point2D_CreatePolar(double radius, double angle_deg) {
|
||||
assert(radius >= 0.0);
|
||||
assert((angle_deg >= 0.0) && (angle_deg < 360.0));
|
||||
|
||||
double angle_radians = angle_deg * DEG_TO_RAD;
|
||||
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
p->x = radius * cos(angle_radians);
|
||||
p->y = radius * sin(angle_radians);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void Point2D_Destroy(Point2D** p) {
|
||||
assert(*p != NULL);
|
||||
free(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
double Point2D_GetX(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->x;
|
||||
}
|
||||
|
||||
double Point2D_GetY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->y;
|
||||
}
|
||||
|
||||
double Point2D_GetRadius(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
return sqrt(p->x * p->x + p->y * p->y);
|
||||
}
|
||||
|
||||
// Returns angle in range [0, 360[ degrees
|
||||
double Point2D_GetAngleDegrees(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
// In range [-180, 180]
|
||||
double angle = atan2(p->y, p->x) * RAD_TO_DEG;
|
||||
|
||||
// In range [0, 360]
|
||||
angle = (angle >= 0) ? angle : angle + 360.0;
|
||||
|
||||
if (angle == 360.0) {
|
||||
angle = 0.0;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
int Point2D_IsEqual(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->x == p2->x) && (p1->y == p2->y);
|
||||
}
|
||||
|
||||
int Point2D_IsDifferent(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->x != p2->x) || (p1->y != p2->y);
|
||||
}
|
||||
|
||||
void Point2D_DisplayXY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", p->x, p->y);
|
||||
}
|
||||
|
||||
void Point2D_DisplayPolar(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", Point2D_GetRadius(p), Point2D_GetAngleDegrees(p));
|
||||
}
|
||||
|
||||
double Point2D_Distance(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double deltaX = p2->x - p1->x;
|
||||
double deltaY = p2->y - p1->y;
|
||||
|
||||
return sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
}
|
||||
|
||||
Point2D* Point2D_MidPoint(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double mid_point_x = (p1->x + p2->x) / 2.0;
|
||||
double mid_point_y = (p1->y + p2->y) / 2.0;
|
||||
|
||||
return Point2D_CreateXY(mid_point_x, mid_point_y);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
Two different internal representations for the Point2D abstract type.
|
||||
|
||||
BUT, just one Point2D.h header file and one testing_Point2D.c file.
|
||||
|
||||
Compile with
|
||||
|
||||
gcc -Wall -Wextra testing_Point2D.c Point2D_XY.c -o testing_Point2D_XY
|
||||
|
||||
gcc -Wall -Wextra testing_Point2D.c Point2D_Polar.c -o testing_Point2D_Polar
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Point2D.h"
|
||||
|
||||
int main(void) {
|
||||
// Some vey simple tests
|
||||
// TO DO : more thorough tests
|
||||
// TO DO : check for floating point precision errors, when comparing for
|
||||
// equality
|
||||
|
||||
// XY (0,0)
|
||||
Point2D* point_1 = Point2D_CreateXY(0.0, 0.0);
|
||||
assert(Point2D_GetX(point_1) == 0.0);
|
||||
assert(Point2D_GetY(point_1) == 0.0);
|
||||
assert(Point2D_GetRadius(point_1) == 0.0);
|
||||
assert(Point2D_GetAngleDegrees(point_1) == 0.0);
|
||||
|
||||
// XY (1,0)
|
||||
Point2D* point_2 = Point2D_CreateXY(1.0, 0.0);
|
||||
assert(Point2D_GetX(point_2) == 1.0);
|
||||
assert(Point2D_GetY(point_2) == 0.0);
|
||||
assert(Point2D_GetRadius(point_2) == 1.0);
|
||||
assert(Point2D_GetAngleDegrees(point_2) == 0.0);
|
||||
|
||||
// Polar: radius = 2.0 and angle = 0 degrees
|
||||
Point2D* point_3 = Point2D_CreatePolar(2.0, 0.0);
|
||||
assert(Point2D_GetX(point_3) == 2.0);
|
||||
assert(Point2D_GetY(point_3) == 0.0);
|
||||
assert(Point2D_GetRadius(point_3) == 2.0);
|
||||
assert(Point2D_GetAngleDegrees(point_3) == 0.0);
|
||||
|
||||
// Comparing
|
||||
assert(Point2D_IsEqual(point_2, point_2));
|
||||
assert(!Point2D_IsEqual(point_2, point_3));
|
||||
assert(!Point2D_IsDifferent(point_2, point_2));
|
||||
assert(Point2D_IsDifferent(point_2, point_3));
|
||||
|
||||
// Distance
|
||||
assert(Point2D_Distance(point_1, point_2) == 1.0);
|
||||
|
||||
// Mid-point
|
||||
Point2D* midpoint = Point2D_MidPoint(point_1, point_2);
|
||||
assert(Point2D_GetX(midpoint) == 0.5);
|
||||
assert(Point2D_GetY(midpoint) == 0.0);
|
||||
|
||||
// Destroy points
|
||||
Point2D_Destroy(&point_1);
|
||||
assert(point_1 == NULL);
|
||||
Point2D_Destroy(&point_2);
|
||||
Point2D_Destroy(&point_3);
|
||||
Point2D_Destroy(&midpoint);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - April 2020
|
||||
//
|
||||
// Writing the digits of a decimal number in reverse order
|
||||
//
|
||||
// Integers STACK : usage example
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "IntegersStack.h"
|
||||
|
||||
int main(void) {
|
||||
int number;
|
||||
|
||||
printf("Write a positive integer value:\n");
|
||||
|
||||
scanf("%d", &number);
|
||||
|
||||
// Creating an empty STACK for integers
|
||||
|
||||
Stack* s1 = StackCreate(20);
|
||||
|
||||
// Get each digit and push it into the stack
|
||||
// LS digit to MS digit
|
||||
|
||||
while (number != 0) {
|
||||
int digit = number % 10;
|
||||
|
||||
StackPush(s1, digit);
|
||||
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
// Get the reversed order using a second stack
|
||||
|
||||
Stack* s2 = StackCreate(20);
|
||||
|
||||
while (!StackIsEmpty(s1)) {
|
||||
int digit = StackPop(s1);
|
||||
|
||||
StackPush(s2, digit);
|
||||
}
|
||||
|
||||
// Destroy the empty stack
|
||||
|
||||
StackDestroy(&s1);
|
||||
|
||||
// Pop from the stack and print
|
||||
|
||||
printf("The reversed number:\n");
|
||||
|
||||
while (!StackIsEmpty(s2)) {
|
||||
int digit;
|
||||
|
||||
digit = StackPop(s2);
|
||||
|
||||
printf("%d", digit);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - April 2020
|
||||
//
|
||||
// Writing the digits of a decimal number in reverse order
|
||||
//
|
||||
// Pointers STACK : usage example
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersStack.h"
|
||||
|
||||
int main(void) {
|
||||
int number;
|
||||
|
||||
printf("Write a positive integer value:\n");
|
||||
|
||||
scanf("%d", &number);
|
||||
|
||||
// Creating an empty STACK for integers
|
||||
|
||||
Stack* s1 = StackCreate(20);
|
||||
|
||||
// Get each digit and push it into the stack
|
||||
// LS digit to MS digit
|
||||
|
||||
while (number != 0) {
|
||||
int* p = malloc(sizeof(int));
|
||||
|
||||
*p = number % 10;
|
||||
|
||||
StackPush(s1, p);
|
||||
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
// Get the reversed order using a second stack
|
||||
|
||||
Stack* s2 = StackCreate(20);
|
||||
|
||||
while (!StackIsEmpty(s1)) {
|
||||
int* p = (int*)StackPop(s1);
|
||||
|
||||
StackPush(s2, p);
|
||||
}
|
||||
|
||||
// Destroy the empty stack
|
||||
|
||||
StackDestroy(&s1);
|
||||
|
||||
// Pop from the stack and print
|
||||
|
||||
printf("The reversed number:\n");
|
||||
|
||||
while (!StackIsEmpty(s2)) {
|
||||
int* p;
|
||||
|
||||
p = (int*)StackPop(s2);
|
||||
|
||||
printf("%d", *p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
// Destroy the empty stack
|
||||
|
||||
StackDestroy(&s2);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - October 2023
|
||||
//
|
||||
// Creating a STACK of 2D Points using the Point2D abstract type
|
||||
//
|
||||
// Pointers STACK : usage example
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Point2D.h"
|
||||
#include "PointersStack.h"
|
||||
|
||||
int main(void) {
|
||||
// Some 2D points
|
||||
Point2D* point_1 = Point2D_CreateXY(0.0, 0.0);
|
||||
Point2D* point_2 = Point2D_CreateXY(1.0, 0.0);
|
||||
Point2D* point_3 = Point2D_CreatePolar(2.0, 0.0);
|
||||
|
||||
// Creating an empty STACK
|
||||
Stack* s = StackCreate(20);
|
||||
|
||||
// Pushing the points onto the STACK
|
||||
StackPush(s, point_1);
|
||||
StackPush(s, point_2);
|
||||
StackPush(s, point_3);
|
||||
|
||||
while (!StackIsEmpty(s)) {
|
||||
Point2D* p = (Point2D*)StackPop(s);
|
||||
Point2D_DisplayXY(p);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Destroy the empty stack
|
||||
StackDestroy(&s);
|
||||
|
||||
// Destroy the points
|
||||
Point2D_Destroy(&point_1);
|
||||
Point2D_Destroy(&point_2);
|
||||
Point2D_Destroy(&point_3);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - April 2020
|
||||
//
|
||||
// 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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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 >= 10 && size <= 1000000);
|
||||
Stack* s = (Stack*)malloc(sizeof(Stack));
|
||||
if (s == NULL) return NULL;
|
||||
s->max_size = size;
|
||||
s->cur_size = 0;
|
||||
s->data = (int*)malloc(size * sizeof(int));
|
||||
if (s->data == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
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) ? 1 : 0; }
|
||||
|
||||
int StackIsEmpty(const Stack* s) { return (s->cur_size == 0) ? 1 : 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)];
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - April 2020
|
||||
//
|
||||
// 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_
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#ifndef _POINT2D_H_
|
||||
#define _POINT2D_H_
|
||||
|
||||
typedef struct _Point2D Point2D;
|
||||
|
||||
Point2D* Point2D_CreateXY(double x, double y);
|
||||
Point2D* Point2D_CreatePolar(double radius, double angle_deg);
|
||||
|
||||
void Point2D_Destroy(Point2D** p);
|
||||
|
||||
double Point2D_GetX(const Point2D* p);
|
||||
double Point2D_GetY(const Point2D* p);
|
||||
|
||||
double Point2D_GetRadius(const Point2D* p);
|
||||
double Point2D_GetAngleDegrees(const Point2D* p);
|
||||
|
||||
int Point2D_IsEqual(const Point2D* p1, const Point2D* p2);
|
||||
int Point2D_IsDifferent(const Point2D* p1, const Point2D* p2);
|
||||
|
||||
void Point2D_DisplayXY(const Point2D* p);
|
||||
void Point2D_DisplayPolar(const Point2D* p);
|
||||
|
||||
double Point2D_Distance(const Point2D* p1, const Point2D* p2);
|
||||
|
||||
Point2D* Point2D_MidPoint(const Point2D* p1, const Point2D* p2);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,137 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Point2D.h"
|
||||
|
||||
// Conversion factors
|
||||
#define RAD_TO_DEG 57.2957795
|
||||
#define DEG_TO_RAD 0.0174532925
|
||||
|
||||
// PI
|
||||
#define PI 3.1415926536
|
||||
|
||||
// radius >= 0
|
||||
// angle in range [0, 2 * PI[
|
||||
struct _Point2D {
|
||||
double radius;
|
||||
double angle;
|
||||
};
|
||||
|
||||
Point2D* Point2D_CreateXY(double x, double y) {
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
|
||||
p->radius = sqrt(x * x + y * y);
|
||||
|
||||
if (y == 0.0) {
|
||||
if (x >= 0.0) {
|
||||
p->angle = 0.0;
|
||||
} else {
|
||||
p->angle = PI;
|
||||
}
|
||||
} else if (x == 0.0) {
|
||||
if (y > 0.0) {
|
||||
p->angle = PI / 2.0;
|
||||
} else {
|
||||
p->angle = 3.0 * PI / 4.0;
|
||||
}
|
||||
} else {
|
||||
// In range ]-PI,PI[
|
||||
double angle = atan2(y, x);
|
||||
p->angle = (angle >= 0.0) ? angle : angle + PI;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Point2D* Point2D_CreatePolar(double radius, double angle_deg) {
|
||||
assert(radius >= 0.0);
|
||||
assert((angle_deg >= 0.0) && (angle_deg < 360.0));
|
||||
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
p->radius = radius;
|
||||
p->angle = angle_deg * DEG_TO_RAD;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void Point2D_Destroy(Point2D** p) {
|
||||
assert(*p != NULL);
|
||||
free(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
double Point2D_GetX(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->radius * cos(p->angle);
|
||||
}
|
||||
|
||||
double Point2D_GetY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->radius * sin(p->angle);
|
||||
}
|
||||
|
||||
double Point2D_GetRadius(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
return p->radius;
|
||||
}
|
||||
|
||||
double Point2D_GetAngleDegrees(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
return p->angle * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
int Point2D_IsEqual(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->radius == p2->radius) && (p1->angle == p2->angle);
|
||||
}
|
||||
|
||||
int Point2D_IsDifferent(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->radius != p2->radius) || (p1->angle != p2->angle);
|
||||
}
|
||||
|
||||
void Point2D_DisplayXY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", Point2D_GetX(p), Point2D_GetY(p));
|
||||
}
|
||||
|
||||
void Point2D_DisplayPolar(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", p->radius, p->angle);
|
||||
}
|
||||
|
||||
double Point2D_Distance(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double deltaX = Point2D_GetX(p2) - Point2D_GetX(p1);
|
||||
double deltaY = Point2D_GetY(p2) - Point2D_GetY(p1);
|
||||
|
||||
return sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
}
|
||||
|
||||
Point2D* Point2D_MidPoint(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double new_X = (Point2D_GetX(p1) + Point2D_GetX(p2)) / 2.0;
|
||||
double new_Y = (Point2D_GetY(p1) + Point2D_GetY(p2)) / 2.0;
|
||||
|
||||
Point2D* mid_point = Point2D_CreateXY(new_X, new_Y);
|
||||
|
||||
return mid_point;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - Outubro 2023
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Point2D.h"
|
||||
|
||||
// Conversion factors
|
||||
#define RAD_TO_DEG 57.2957795
|
||||
#define DEG_TO_RAD 0.0174532925
|
||||
|
||||
struct _Point2D {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
Point2D* Point2D_CreateXY(double x, double y) {
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
p->x = x;
|
||||
p->y = y;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Point2D* Point2D_CreatePolar(double radius, double angle_deg) {
|
||||
assert(radius >= 0.0);
|
||||
assert((angle_deg >= 0.0) && (angle_deg < 360.0));
|
||||
|
||||
double angle_radians = angle_deg * DEG_TO_RAD;
|
||||
|
||||
Point2D* p = malloc(sizeof(Point2D));
|
||||
assert(p != NULL);
|
||||
p->x = radius * cos(angle_radians);
|
||||
p->y = radius * sin(angle_radians);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void Point2D_Destroy(Point2D** p) {
|
||||
assert(*p != NULL);
|
||||
free(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
double Point2D_GetX(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->x;
|
||||
}
|
||||
|
||||
double Point2D_GetY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
return p->y;
|
||||
}
|
||||
|
||||
double Point2D_GetRadius(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
return sqrt(p->x * p->x + p->y * p->y);
|
||||
}
|
||||
|
||||
// Returns angle in range [0, 360[ degrees
|
||||
double Point2D_GetAngleDegrees(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
// In range [-180, 180]
|
||||
double angle = atan2(p->y, p->x) * RAD_TO_DEG;
|
||||
|
||||
// In range [0, 360]
|
||||
angle = (angle >= 0) ? angle : angle + 360.0;
|
||||
|
||||
if (angle == 360.0) {
|
||||
angle = 0.0;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
int Point2D_IsEqual(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->x == p2->x) && (p1->y == p2->y);
|
||||
}
|
||||
|
||||
int Point2D_IsDifferent(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
return (p1->x != p2->x) || (p1->y != p2->y);
|
||||
}
|
||||
|
||||
void Point2D_DisplayXY(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", p->x, p->y);
|
||||
}
|
||||
|
||||
void Point2D_DisplayPolar(const Point2D* p) {
|
||||
assert(p != NULL);
|
||||
|
||||
printf("( %.3f, %.3f )", Point2D_GetRadius(p), Point2D_GetAngleDegrees(p));
|
||||
}
|
||||
|
||||
double Point2D_Distance(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double deltaX = p2->x - p1->x;
|
||||
double deltaY = p2->y - p1->y;
|
||||
|
||||
return sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
}
|
||||
|
||||
Point2D* Point2D_MidPoint(const Point2D* p1, const Point2D* p2) {
|
||||
assert((p1 != NULL) && (p2 != NULL));
|
||||
|
||||
double mid_point_x = (p1->x + p2->x) / 2.0;
|
||||
double mid_point_y = (p1->y + p2->y) / 2.0;
|
||||
|
||||
return Point2D_CreateXY(mid_point_x, mid_point_y);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - April 2020
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on an array of
|
||||
// pointers to void
|
||||
//
|
||||
|
||||
#include "PointersStack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersStack {
|
||||
int max_size; // maximum stack size
|
||||
int cur_size; // current stack size
|
||||
void** data; // the stack data (pointers stored in an array)
|
||||
};
|
||||
|
||||
Stack* StackCreate(int size) {
|
||||
assert(size >= 10 && size <= 1000000);
|
||||
Stack* s = (Stack*)malloc(sizeof(Stack));
|
||||
if (s == NULL) return NULL;
|
||||
s->max_size = size;
|
||||
s->cur_size = 0;
|
||||
s->data = (void**)malloc(size * sizeof(void*));
|
||||
if (s->data == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
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) ? 1 : 0; }
|
||||
|
||||
int StackIsEmpty(const Stack* s) { return (s->cur_size == 0) ? 1 : 0; }
|
||||
|
||||
void* StackPeek(const Stack* s) {
|
||||
assert(s->cur_size > 0);
|
||||
return s->data[s->cur_size - 1];
|
||||
}
|
||||
|
||||
void StackPush(Stack* s, void* p) {
|
||||
assert(s->cur_size < s->max_size);
|
||||
s->data[s->cur_size++] = p;
|
||||
}
|
||||
|
||||
void* StackPop(Stack* s) {
|
||||
assert(s->cur_size > 0);
|
||||
return s->data[--(s->cur_size)];
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// J. Madeira - April 2020
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on an array of
|
||||
// pointers to void
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_STACK_
|
||||
#define _POINTERS_STACK_
|
||||
|
||||
typedef struct _PointersStack 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);
|
||||
|
||||
void* StackPeek(const Stack* s);
|
||||
|
||||
void StackPush(Stack* s, void* p);
|
||||
|
||||
void* StackPop(Stack* s);
|
||||
|
||||
#endif // _POINTERS_STACK_
|
|
@ -0,0 +1,11 @@
|
|||
Simple examples --- Compile with
|
||||
|
||||
gcc -Wall -Wextra 01_example_IntegersSTACK.c IntegersStack.c -o 01_example_IntegersSTACK
|
||||
|
||||
gcc -Wall -Wextra 02_example_PointersSTACK.c PointersStack.c -o 02_example_PointersSTACK
|
||||
|
||||
STACK of pointers to 2D Points --- Compile with
|
||||
|
||||
gcc -Wall -Wextra PointersStack.c Point2D_XY.c 03_example_STACK_Point2D.c -o 03_example_Point2D_STACK
|
||||
|
||||
gcc -Wall -Wextra PointersStack.c Point2D_Polar.c 03_example_STACK_Point2D.c -o 03_example_Point2D_STACK
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
// João Manuel Rodrigues, May 2020
|
||||
//
|
||||
// Integers queue (First In First Out) implementation based on a circular array
|
||||
|
||||
#include "IntegersQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _IntegersQueue {
|
||||
int max_size; // maximum Queue size
|
||||
int cur_size; // current Queue size
|
||||
int head;
|
||||
int tail;
|
||||
int* data; // the Queue data (integers stored in an array)
|
||||
};
|
||||
|
||||
// PRIVATE auxiliary function
|
||||
|
||||
static int increment_index(const Queue* q, int i) {
|
||||
return (i + 1 < q->max_size) ? i + 1 : 0;
|
||||
}
|
||||
|
||||
// PUBLIC functions
|
||||
|
||||
Queue* QueueCreate(int size) {
|
||||
assert(size >= 10 && size <= 1000000);
|
||||
Queue* q = (Queue*)malloc(sizeof(Queue));
|
||||
if (q == NULL) return NULL;
|
||||
|
||||
q->max_size = size;
|
||||
q->cur_size = 0;
|
||||
|
||||
q->head = 1; // cur_size = tail - head + 1
|
||||
q->tail = 0;
|
||||
|
||||
q->data = (int*)malloc(size * sizeof(int));
|
||||
if (q->data == NULL) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void QueueDestroy(Queue** p) {
|
||||
assert(*p != NULL);
|
||||
Queue* q = *p;
|
||||
free(q->data);
|
||||
free(q);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void QueueClear(Queue* q) {
|
||||
q->cur_size = 0;
|
||||
q->head = 1; // cur_size = tail - head + 1
|
||||
q->tail = 0;
|
||||
}
|
||||
|
||||
int QueueSize(const Queue* q) { return q->cur_size; }
|
||||
|
||||
int QueueIsFull(const Queue* q) { return (q->cur_size == q->max_size) ? 1 : 0; }
|
||||
|
||||
int QueueIsEmpty(const Queue* q) { return (q->cur_size == 0) ? 1 : 0; }
|
||||
|
||||
int QueuePeek(const Queue* q) {
|
||||
assert(q->cur_size > 0);
|
||||
return q->data[q->head];
|
||||
}
|
||||
|
||||
void QueueEnqueue(Queue* q, int i) {
|
||||
assert(q->cur_size < q->max_size);
|
||||
q->tail = increment_index(q, q->tail);
|
||||
q->data[q->tail] = i;
|
||||
q->cur_size++;
|
||||
}
|
||||
|
||||
int QueueDequeue(Queue* q) {
|
||||
assert(q->cur_size > 0);
|
||||
int old_head = q->head;
|
||||
q->head = increment_index(q, q->head);
|
||||
q->cur_size--;
|
||||
return q->data[old_head];
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// Joaquim Madeira, May 2020
|
||||
// João Manuel Rodrigues, May 2020
|
||||
//
|
||||
// Integers queue (First In First Out) implementation based on a circular array
|
||||
//
|
||||
|
||||
#ifndef _INTEGERS_QUEUE_
|
||||
#define _INTEGERS_QUEUE_
|
||||
|
||||
typedef struct _IntegersQueue Queue;
|
||||
|
||||
Queue* QueueCreate(int size);
|
||||
|
||||
void QueueDestroy(Queue** p);
|
||||
|
||||
void QueueClear(Queue* q);
|
||||
|
||||
int QueueSize(const Queue* q);
|
||||
|
||||
int QueueIsFull(const Queue* q);
|
||||
|
||||
int QueueIsEmpty(const Queue* q);
|
||||
|
||||
int QueuePeek(const Queue* q);
|
||||
|
||||
void QueueEnqueue(Queue* q, int i);
|
||||
|
||||
int QueueDequeue(Queue* q);
|
||||
|
||||
#endif // _INTEGERS_QUEUE_
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on a circular
|
||||
// array of pointers to void
|
||||
//
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersQueue {
|
||||
int max_size; // maximum Queue size
|
||||
int cur_size; // current Queue size
|
||||
int head;
|
||||
int tail;
|
||||
void** data; // the Queue data (pointers stored in an array)
|
||||
};
|
||||
|
||||
// PRIVATE auxiliary function
|
||||
|
||||
static int increment_index(const Queue* q, int i) {
|
||||
return (i + 1 < q->max_size) ? i + 1 : 0;
|
||||
}
|
||||
|
||||
// PUBLIC functions
|
||||
|
||||
Queue* QueueCreate(int size) {
|
||||
assert(size >= 10 && size <= 1000000);
|
||||
Queue* q = (Queue*)malloc(sizeof(Queue));
|
||||
if (q == NULL) return NULL;
|
||||
|
||||
q->max_size = size;
|
||||
q->cur_size = 0;
|
||||
|
||||
q->head = 1; // cur_size = tail - head + 1
|
||||
q->tail = 0;
|
||||
|
||||
q->data = (void**)malloc(size * sizeof(void*));
|
||||
if (q->data == NULL) {
|
||||
free(q);
|
||||
return NULL;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
void QueueDestroy(Queue** p) {
|
||||
assert(*p != NULL);
|
||||
Queue* q = *p;
|
||||
free(q->data);
|
||||
free(q);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void QueueClear(Queue* q) {
|
||||
q->cur_size = 0;
|
||||
q->head = 1; // cur_size = tail - head + 1
|
||||
q->tail = 0;
|
||||
}
|
||||
|
||||
int QueueSize(const Queue* q) { return q->cur_size; }
|
||||
|
||||
int QueueIsFull(const Queue* q) { return (q->cur_size == q->max_size) ? 1 : 0; }
|
||||
|
||||
int QueueIsEmpty(const Queue* q) { return (q->cur_size == 0) ? 1 : 0; }
|
||||
|
||||
void* QueuePeek(const Queue* q) {
|
||||
assert(q->cur_size > 0);
|
||||
return q->data[q->head];
|
||||
}
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p) {
|
||||
assert(q->cur_size < q->max_size);
|
||||
q->tail = increment_index(q, q->tail);
|
||||
q->data[q->tail] = p;
|
||||
q->cur_size++;
|
||||
}
|
||||
|
||||
void* QueueDequeue(Queue* q) {
|
||||
assert(q->cur_size > 0);
|
||||
int old_head = q->head;
|
||||
q->head = increment_index(q, q->head);
|
||||
q->cur_size--;
|
||||
return q->data[old_head];
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on a circular array
|
||||
// of pointers to void
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_QUEUE_
|
||||
#define _POINTERS_QUEUE_
|
||||
|
||||
typedef struct _PointersQueue Queue;
|
||||
|
||||
Queue* QueueCreate(int size);
|
||||
|
||||
void QueueDestroy(Queue** p);
|
||||
|
||||
void QueueClear(Queue* q);
|
||||
|
||||
int QueueSize(const Queue* q);
|
||||
|
||||
int QueueIsFull(const Queue* q);
|
||||
|
||||
int QueueIsEmpty(const Queue* q);
|
||||
|
||||
void* QueuePeek(const Queue* q);
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p);
|
||||
|
||||
void* QueueDequeue(Queue* q);
|
||||
|
||||
#endif // _POINTERS_QUEUE_
|
|
@ -0,0 +1,10 @@
|
|||
Simple examples --- Compile with
|
||||
|
||||
gcc -Wall -Wextra testing_IntegersQueue.c IntegersQueue.c -o testing_IntegersQueue
|
||||
|
||||
gcc -Wall -Wextra testing_PointersQueue.c PointersQueue.c -o testing_PointersQueue
|
||||
|
||||
|
||||
TASK --- Neew example
|
||||
|
||||
Create a QUEUE of 2D points and test it !!
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Integers queue (First In First Out) implementation based on an array
|
||||
//
|
||||
// TESTING the implementation
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "IntegersQueue.h"
|
||||
|
||||
int main(void) {
|
||||
Queue* Q = QueueCreate(100);
|
||||
|
||||
int i = 0;
|
||||
int o = 0;
|
||||
|
||||
for (int n = 0; n < 2000000; n++) {
|
||||
if (QueueSize(Q) == 0 ||
|
||||
(QueueSize(Q) < 20 && (rand() & 0x01000000) == 0)) {
|
||||
QueueEnqueue(Q, i);
|
||||
i++;
|
||||
} else {
|
||||
int aux = QueueDequeue(Q);
|
||||
assert(aux == o);
|
||||
o++;
|
||||
}
|
||||
if (QueueSize(Q) > 0) {
|
||||
int aux = QueuePeek(Q);
|
||||
assert(aux == o);
|
||||
}
|
||||
}
|
||||
while (QueueSize(Q) > 0) {
|
||||
int aux = QueueDequeue(Q);
|
||||
printf("%d\n", aux);
|
||||
}
|
||||
|
||||
printf("All is well [i = %d, o = %d]\n", i, o);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
//
|
||||
// Algoritmos e Estruturas de Dados - 2023/2024 - 1o semestre
|
||||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on an array
|
||||
// of pointers to void
|
||||
//
|
||||
// TESTING the implementation
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
int main(void) {
|
||||
Queue* Q = QueueCreate(100);
|
||||
|
||||
int i = 0;
|
||||
int o = 0;
|
||||
|
||||
for (int n = 0; n < 2000000; n++) {
|
||||
if (QueueSize(Q) == 0 ||
|
||||
(QueueSize(Q) < 20 && (rand() & 0x01000000) == 0)) {
|
||||
int* aux = malloc(sizeof(int));
|
||||
*aux = i;
|
||||
QueueEnqueue(Q, aux);
|
||||
i++;
|
||||
} else {
|
||||
int* aux = (int*)QueueDequeue(Q);
|
||||
assert(*aux == o);
|
||||
o++;
|
||||
free(aux);
|
||||
}
|
||||
if (QueueSize(Q) > 0) {
|
||||
int* aux = (int*)QueuePeek(Q);
|
||||
assert(*aux == o);
|
||||
}
|
||||
}
|
||||
while (QueueSize(Q) > 0) {
|
||||
int* aux = (int*)QueueDequeue(Q);
|
||||
printf("%d\n", *aux);
|
||||
free(aux);
|
||||
}
|
||||
|
||||
printf("All is well [i = %d, o = %d]\n", i, o);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
TASKS
|
||||
|
||||
1 - Specify the interface for the DEQUE abstract type - PointersDeque.h
|
||||
|
||||
2 - Use a CIRCULAR ARRAY for the internal representation - PointersDeque.c
|
||||
|
||||
3 - Implement the required functions
|
||||
|
||||
4 - Test your code with different application examples
|
||||
|
||||
SUGGESTION: use as a basis the QUEUE abstract type implemented with a CIRCULAR ARRAY
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
/*****************************************************************************
|
||||
***
|
||||
*** Algoritmos e Complexidade
|
||||
***
|
||||
*** Ano lectivo 2019/2020 --- 2o. Semestre
|
||||
***
|
||||
*** DETI - Universidade de Aveiro
|
||||
***
|
||||
*****************************************************************************
|
||||
***
|
||||
*** Ficheiro: 01_exemplo_PointersSTACK.c
|
||||
*** Autor: Joaquim Madeira
|
||||
*** Data: 22/04/2020
|
||||
*** Versao: 1.00
|
||||
***
|
||||
*****************************************************************************
|
||||
***
|
||||
*** Informacao:
|
||||
***
|
||||
*** Escrever os algarismos de um numero pela ordem inversa.
|
||||
***
|
||||
*** STACK generico de ponteiros: exemplo de utilizacao
|
||||
***
|
||||
*****************************************************************************
|
||||
***
|
||||
*** Alteracoes: 0.0 22/04/2020 Autor
|
||||
***
|
||||
*** Sem alteracoess.
|
||||
***
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersStack.h"
|
||||
|
||||
int main(void) {
|
||||
int number;
|
||||
|
||||
printf("Write a positive integer value:\n");
|
||||
|
||||
scanf("%d", &number);
|
||||
|
||||
// Creating an empty STACK for integers
|
||||
|
||||
Stack* s1 = StackCreate();
|
||||
|
||||
// Get each digit and push it into the stack
|
||||
// LS digit to MS digit
|
||||
|
||||
while (number != 0) {
|
||||
int* p = malloc(sizeof(int));
|
||||
|
||||
*p = number % 10;
|
||||
|
||||
StackPush(s1, p);
|
||||
|
||||
number /= 10;
|
||||
}
|
||||
|
||||
// Get the reversed order using a second stack
|
||||
|
||||
Stack* s2 = StackCreate();
|
||||
|
||||
while (!StackIsEmpty(s1)) {
|
||||
int* p = (int*)StackPop(s1);
|
||||
|
||||
StackPush(s2, p);
|
||||
}
|
||||
|
||||
// Destroy the empty stack
|
||||
|
||||
StackDestroy(&s1);
|
||||
|
||||
// Pop from the stack and print
|
||||
|
||||
printf("The reversed number:\n");
|
||||
|
||||
while (!StackIsEmpty(s2)) {
|
||||
int* p;
|
||||
|
||||
p = (int*)StackPop(s2);
|
||||
|
||||
printf("%d", *p);
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
// Destroy the empty stack
|
||||
|
||||
StackDestroy(&s2);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersStack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersStackNode {
|
||||
void* data;
|
||||
struct _PointersStackNode* next;
|
||||
};
|
||||
|
||||
struct _PointersStack {
|
||||
int cur_size; // current stack size
|
||||
struct _PointersStackNode* top; // the node on the top of the stack
|
||||
};
|
||||
|
||||
Stack* StackCreate(void) {
|
||||
Stack* s = (Stack*)malloc(sizeof(Stack));
|
||||
assert(s != NULL);
|
||||
|
||||
s->cur_size = 0;
|
||||
s->top = NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
void StackDestroy(Stack** p) {
|
||||
assert(*p != NULL);
|
||||
Stack* s = *p;
|
||||
|
||||
StackClear(s);
|
||||
|
||||
free(s);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void StackClear(Stack* s) {
|
||||
assert(s != NULL);
|
||||
|
||||
struct _PointersStackNode* p = s->top;
|
||||
struct _PointersStackNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
s->cur_size = 0;
|
||||
s->top = NULL;
|
||||
}
|
||||
|
||||
int StackSize(const Stack* s) {
|
||||
assert(s != NULL);
|
||||
return s->cur_size;
|
||||
}
|
||||
|
||||
int StackIsEmpty(const Stack* s) {
|
||||
assert(s != NULL);
|
||||
return (s->cur_size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* StackPeek(const Stack* s) {
|
||||
assert(s != NULL && s->cur_size > 0);
|
||||
return s->top->data;
|
||||
}
|
||||
|
||||
void StackPush(Stack* s, void* p) {
|
||||
assert(s != NULL);
|
||||
|
||||
struct _PointersStackNode* aux;
|
||||
aux = (struct _PointersStackNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = s->top;
|
||||
|
||||
s->top = aux;
|
||||
|
||||
s->cur_size++;
|
||||
}
|
||||
|
||||
void* StackPop(Stack* s) {
|
||||
assert(s != NULL && s->cur_size > 0);
|
||||
|
||||
struct _PointersStackNode* aux = s->top;
|
||||
s->top = aux->next;
|
||||
s->cur_size--;
|
||||
|
||||
void* p = aux->data;
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_STACK_
|
||||
#define _POINTERS_STACK_
|
||||
|
||||
typedef struct _PointersStack Stack;
|
||||
|
||||
Stack* StackCreate(void);
|
||||
|
||||
void StackDestroy(Stack** p);
|
||||
|
||||
void StackClear(Stack* s);
|
||||
|
||||
int StackSize(const Stack* s);
|
||||
|
||||
int StackIsEmpty(const Stack* s);
|
||||
|
||||
void* StackPeek(const Stack* s);
|
||||
|
||||
void StackPush(Stack* s, void* p);
|
||||
|
||||
void* StackPop(Stack* s);
|
||||
|
||||
#endif // _POINTERS_STACK_
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersQueueNode {
|
||||
void* data;
|
||||
struct _PointersQueueNode* next;
|
||||
};
|
||||
|
||||
struct _PointersQueue {
|
||||
int size; // current Queue size
|
||||
struct _PointersQueueNode* head; // the head of the Queue
|
||||
struct _PointersQueueNode* tail; // the tail of the Queue
|
||||
};
|
||||
|
||||
Queue* QueueCreate(void) {
|
||||
Queue* q = (Queue*)malloc(sizeof(Queue));
|
||||
assert(q != NULL);
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
return q;
|
||||
}
|
||||
|
||||
void QueueDestroy(Queue** p) {
|
||||
assert(*p != NULL);
|
||||
Queue* q = *p;
|
||||
|
||||
QueueClear(q);
|
||||
|
||||
free(q);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void QueueClear(Queue* q) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* p = q->head;
|
||||
struct _PointersQueueNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
int QueueSize(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return q->size;
|
||||
}
|
||||
|
||||
int QueueIsEmpty(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return (q->size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* QueuePeek(const Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
return q->head->data;
|
||||
}
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* aux;
|
||||
aux = (struct _PointersQueueNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = NULL;
|
||||
|
||||
q->size++;
|
||||
|
||||
if (q->size == 1) {
|
||||
q->head = aux;
|
||||
q->tail = aux;
|
||||
} else {
|
||||
q->tail->next = aux;
|
||||
q->tail = aux;
|
||||
}
|
||||
}
|
||||
|
||||
void* QueueDequeue(Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
|
||||
struct _PointersQueueNode* aux = q->head;
|
||||
void* p = aux->data;
|
||||
|
||||
q->size--;
|
||||
|
||||
if (q->size == 0) {
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
} else {
|
||||
q->head = aux->next;
|
||||
}
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_QUEUE_
|
||||
|
||||
#define _POINTERS_QUEUE_
|
||||
|
||||
typedef struct _PointersQueue Queue;
|
||||
|
||||
Queue* QueueCreate(void);
|
||||
|
||||
void QueueDestroy(Queue** p);
|
||||
|
||||
void QueueClear(Queue* q);
|
||||
|
||||
int QueueSize(const Queue* q);
|
||||
|
||||
int QueueIsEmpty(const Queue* q);
|
||||
|
||||
void* QueuePeek(const Queue* q);
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p);
|
||||
|
||||
void* QueueDequeue(Queue* q);
|
||||
|
||||
#endif // _POINTERS_QUEUE_
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
///
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
// TESTING the implementation
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
int main(void) {
|
||||
Queue* Q = QueueCreate();
|
||||
|
||||
int i = 0;
|
||||
int o = 0;
|
||||
|
||||
for (int n = 0; n < 2000000; n++) {
|
||||
if (QueueSize(Q) == 0 ||
|
||||
(QueueSize(Q) < 20 && (rand() & 0x01000000) == 0)) {
|
||||
int* aux = malloc(sizeof(int));
|
||||
*aux = i;
|
||||
QueueEnqueue(Q, aux);
|
||||
i++;
|
||||
} else {
|
||||
int* aux = (int*)QueueDequeue(Q);
|
||||
assert(*aux == o);
|
||||
o++;
|
||||
free(aux);
|
||||
}
|
||||
if (QueueSize(Q) > 0) {
|
||||
int* aux = (int*)QueuePeek(Q);
|
||||
assert(*aux == o);
|
||||
}
|
||||
}
|
||||
while (QueueSize(Q) > 0) {
|
||||
int* aux = (int*)QueueDequeue(Q);
|
||||
printf("%d\n", *aux);
|
||||
free(aux);
|
||||
}
|
||||
|
||||
printf("All is well [i = %d, o = %d]\n", i, o);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers LIST implementation based on an linked list
|
||||
//
|
||||
|
||||
// ***************** COMPLETAR AS FUNCOES !!! *******************
|
||||
|
||||
#include "PointersList.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersListNode {
|
||||
void* data;
|
||||
struct _PointersListNode* next;
|
||||
};
|
||||
|
||||
struct _PointersList {
|
||||
int size; // current List size
|
||||
struct _PointersListNode* head; // the head of the List
|
||||
struct _PointersListNode* tail; // the tail of the List
|
||||
struct _PointersListNode* current; // the current node
|
||||
int currentPos;
|
||||
};
|
||||
|
||||
List* ListCreate(void) {
|
||||
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
|
||||
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 _PointersListNode* p = l->head;
|
||||
struct _PointersListNode* 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* ListGetCurrentValue(const List* l) {
|
||||
assert(l != NULL && l->current != NULL);
|
||||
return l->current->data;
|
||||
}
|
||||
|
||||
void ListModifyCurrentValue(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 ListSearchFromCurrent(const List* l, void* p) { return -1; }
|
||||
|
||||
// Move to functions
|
||||
|
||||
int ListMove(List* l, int newPos) { return -1; }
|
||||
|
||||
int ListMoveToNext(List* l) { return -1; }
|
||||
|
||||
int ListMoveToPrevious(List* l) { return -1; }
|
||||
|
||||
int ListMoveToHead(List* l) { return -1; }
|
||||
|
||||
int ListMoveToTail(List* l) { return -1; }
|
||||
|
||||
// Insert functions
|
||||
|
||||
void ListInsertBeforeHead(List* l, void* p) {}
|
||||
|
||||
void ListInsertAfterTail(List* l, void* p) {}
|
||||
|
||||
void ListInsertAfterCurrent(List* l, void* p) {}
|
||||
|
||||
void ListInsertBeforeCurrent(List* l, void* p) {}
|
||||
|
||||
// Remove functions
|
||||
|
||||
void ListRemoveHead(List* l) {
|
||||
assert(l != NULL && l->size > 0);
|
||||
|
||||
struct _PointersListNode* aux = l->head;
|
||||
|
||||
if (l->current == l->head) {
|
||||
l->current = l->head->next;
|
||||
if (l->current == NULL) {
|
||||
l->currentPos = -1;
|
||||
} else {
|
||||
l->currentPos++;
|
||||
}
|
||||
}
|
||||
|
||||
l->size--;
|
||||
|
||||
if (l->size == 0) {
|
||||
l->head = NULL;
|
||||
l->tail = NULL;
|
||||
} else {
|
||||
struct _PointersListNode* next = l->head->next;
|
||||
l->head = next;
|
||||
}
|
||||
|
||||
free(aux);
|
||||
}
|
||||
|
||||
void ListRemoveTail(List* l) {}
|
||||
|
||||
void ListRemoveCurrent(List* l) {}
|
||||
|
||||
void ListRemoveNext(List* l) {}
|
||||
|
||||
// Tests
|
||||
|
||||
void ListTestInvariants(const List* l) {}
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Joaquim Madeira, AlgC, April 2020
|
||||
//
|
||||
// Pointers LIST implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_LIST_
|
||||
|
||||
#define _POINTERS_LIST_
|
||||
|
||||
typedef struct _PointersList List;
|
||||
|
||||
List* ListCreate(void);
|
||||
|
||||
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* ListGetCurrentValue(const List* l);
|
||||
|
||||
void ListModifyCurrentValue(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 ListSearchFromCurrent(const List* l, void* p);
|
||||
|
||||
// Move to functions
|
||||
|
||||
int ListMove(List* l, int newPos);
|
||||
|
||||
int ListMoveToNext(List* l);
|
||||
|
||||
int ListMoveToPrevious(List* l);
|
||||
|
||||
int ListMoveToHead(List* l);
|
||||
|
||||
int ListMoveToTail(List* l);
|
||||
|
||||
// Insert functions
|
||||
|
||||
void ListInsertBeforeHead(List* l, void* p);
|
||||
|
||||
void ListInsertAfterTail(List* l, void* p);
|
||||
|
||||
void ListInsertAfterCurrent(List* l, void* p);
|
||||
|
||||
void ListInsertBeforeCurrent(List* l, void* p);
|
||||
|
||||
// Remove functions
|
||||
|
||||
void ListRemoveHead(List* l);
|
||||
|
||||
void ListRemoveTail(List* l);
|
||||
|
||||
void ListRemoveCurrent(List* l);
|
||||
|
||||
void ListRemoveNext(List* l);
|
||||
|
||||
// Tests
|
||||
|
||||
void ListTestInvariants(const List* l);
|
||||
|
||||
#endif // _POINTERS_LIST_
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
1 - Complete the missing functions on the .c file
|
||||
|
||||
2 - Redo the previous application examples !!
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
*** Use ADT POINTERS LIST as a basis for ADT POINTERS DEQUE ***
|
||||
|
||||
1 - Establish the interface of ADT POPINTERS DEQUE, without any reference to the ADT POINTERS LIST - PointersDeque.h
|
||||
|
||||
2 - Establish the internal representation using ADT POINTERS LIST - PointersDeque.c
|
||||
|
||||
3 - Implement the required DEQUE functions, using the corresponding POINTERS LIST functions
|
||||
|
||||
4 - Test with new application examples
|
||||
|
Binary file not shown.
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers LIST implementation based on a linked list
|
||||
//
|
||||
|
||||
// ***************** COMPLETAR AS FUNCOES !!! *******************
|
||||
|
||||
#include "PointersList.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersListNode {
|
||||
void* data;
|
||||
struct _PointersListNode* next;
|
||||
};
|
||||
|
||||
struct _PointersList {
|
||||
int size; // current List size
|
||||
struct _PointersListNode* head; // the head of the List
|
||||
struct _PointersListNode* tail; // the tail of the List
|
||||
struct _PointersListNode* current; // the current node
|
||||
int currentPos;
|
||||
};
|
||||
|
||||
List* ListCreate(void) {
|
||||
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
|
||||
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 _PointersListNode* p = l->head;
|
||||
struct _PointersListNode* 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* ListGetCurrentValue(const List* l) {
|
||||
assert(l != NULL && l->current != NULL);
|
||||
return l->current->data;
|
||||
}
|
||||
|
||||
void ListModifyCurrentValue(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 ListSearchFromCurrent(const List* l, void* p) { return -1; }
|
||||
|
||||
// Move to functions
|
||||
|
||||
int ListMove(List* l, int newPos) { return -1; }
|
||||
|
||||
int ListMoveToNext(List* l) { return -1; }
|
||||
|
||||
int ListMoveToPrevious(List* l) { return -1; }
|
||||
|
||||
int ListMoveToHead(List* l) { return -1; }
|
||||
|
||||
int ListMoveToTail(List* l) { return -1; }
|
||||
|
||||
// Insert functions
|
||||
|
||||
void ListInsertBeforeHead(List* l, void* p) {}
|
||||
|
||||
void ListInsertAfterTail(List* l, void* p) {}
|
||||
|
||||
void ListInsertAfterCurrent(List* l, void* p) {}
|
||||
|
||||
void ListInsertBeforeCurrent(List* l, void* p) {}
|
||||
|
||||
// Remove functions
|
||||
|
||||
void ListRemoveHead(List* l) {
|
||||
assert(l != NULL && l->size > 0);
|
||||
|
||||
struct _PointersListNode* aux = l->head;
|
||||
|
||||
if (l->current == l->head) {
|
||||
l->current = l->head->next;
|
||||
if (l->current == NULL) {
|
||||
l->currentPos = -1;
|
||||
} else {
|
||||
l->currentPos++;
|
||||
}
|
||||
}
|
||||
|
||||
l->size--;
|
||||
|
||||
if (l->size == 0) {
|
||||
l->head = NULL;
|
||||
l->tail = NULL;
|
||||
} else {
|
||||
struct _PointersListNode* next = l->head->next;
|
||||
l->head = next;
|
||||
}
|
||||
|
||||
free(aux);
|
||||
}
|
||||
|
||||
void ListRemoveTail(List* l) {}
|
||||
|
||||
void ListRemoveCurrent(List* l) {}
|
||||
|
||||
void ListRemoveNext(List* l) {}
|
||||
|
||||
// Tests
|
||||
|
||||
void ListTestInvariants(const List* l) {}
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Pointers LIST implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_LIST_
|
||||
|
||||
#define _POINTERS_LIST_
|
||||
|
||||
typedef struct _PointersList List;
|
||||
|
||||
List* ListCreate(void);
|
||||
|
||||
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* ListGetCurrentValue(const List* l);
|
||||
|
||||
void ListModifyCurrentValue(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 ListSearchFromCurrent(const List* l, void* p);
|
||||
|
||||
// Move to functions
|
||||
|
||||
int ListMove(List* l, int newPos);
|
||||
|
||||
int ListMoveToNext(List* l);
|
||||
|
||||
int ListMoveToPrevious(List* l);
|
||||
|
||||
int ListMoveToHead(List* l);
|
||||
|
||||
int ListMoveToTail(List* l);
|
||||
|
||||
// Insert functions
|
||||
|
||||
void ListInsertBeforeHead(List* l, void* p);
|
||||
|
||||
void ListInsertAfterTail(List* l, void* p);
|
||||
|
||||
void ListInsertAfterCurrent(List* l, void* p);
|
||||
|
||||
void ListInsertBeforeCurrent(List* l, void* p);
|
||||
|
||||
// Remove functions
|
||||
|
||||
void ListRemoveHead(List* l);
|
||||
|
||||
void ListRemoveTail(List* l);
|
||||
|
||||
void ListRemoveCurrent(List* l);
|
||||
|
||||
void ListRemoveNext(List* l);
|
||||
|
||||
// Tests
|
||||
|
||||
void ListTestInvariants(const List* l);
|
||||
|
||||
#endif // _POINTERS_LIST_
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
Complete the missing functions on the .c file
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
///
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// TESTING the TAD SORTED LIST implementation
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SortedList.h"
|
||||
|
||||
// Storing pointers to integers
|
||||
|
||||
// The comparator
|
||||
|
||||
int comparator(const void* p1, const void* p2) {
|
||||
int d = *(int*)p1 - *(int*)p2;
|
||||
return (d > 0) - (d < 0);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
List* list = ListCreate(comparator);
|
||||
|
||||
printf("INSERTING\n");
|
||||
|
||||
for (int i = 1; i < 10; i += 2) {
|
||||
int* aux = (int*)malloc(sizeof(int));
|
||||
*aux = i;
|
||||
ListInsert(list, aux);
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 11; i += 2) {
|
||||
int* aux = (int*)malloc(sizeof(int));
|
||||
*aux = i;
|
||||
ListInsert(list, aux);
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
printf("%d elements\n", ListGetSize(list));
|
||||
|
||||
int i = 0;
|
||||
int size = ListGetSize(list);
|
||||
ListMove(list, 0);
|
||||
while (i < size) {
|
||||
int* p = (int*)ListGetCurrentItem(list);
|
||||
printf("%d ", *p);
|
||||
ListMoveToNext(list);
|
||||
i++;
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
printf("\nREMOVING\n");
|
||||
|
||||
ListMoveToHead(list);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int* aux = ListRemoveCurrent(list);
|
||||
free(aux);
|
||||
ListMoveToNext(list);
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
size = ListGetSize(list);
|
||||
ListMove(list, 0);
|
||||
while (i < size) {
|
||||
int* p = (int*)ListGetCurrentItem(list);
|
||||
printf("%d ", *p);
|
||||
ListMoveToNext(list);
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
///
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// TESTING the TAD SORTED LIST implementation
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Date.h"
|
||||
#include "SortedList.h"
|
||||
|
||||
// Storing pointers to integers
|
||||
|
||||
// The comparator
|
||||
|
||||
int comparatorForDates(const void* p1, const void* p2) {
|
||||
return DateCompare((Date*)p1, (Date*)p2);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
List* list = ListCreate(comparatorForDates);
|
||||
|
||||
printf("INSERTING\n");
|
||||
|
||||
for (int i = 2; i < 13; i += 2) {
|
||||
Date* aux = DateCreate(2020, 01, i);
|
||||
ListInsert(list, aux);
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
for (int i = 1; i < 15; i += 2) {
|
||||
Date* aux = DateCreate(2020, 01, i);
|
||||
ListInsert(list, aux);
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
printf("%d elements\n", ListGetSize(list));
|
||||
|
||||
int i = 0;
|
||||
int size = ListGetSize(list);
|
||||
ListMove(list, 0);
|
||||
while (i < size) {
|
||||
Date* p = (Date*)ListGetCurrentItem(list);
|
||||
printf("%s\n", DateFormat(p, DMY));
|
||||
ListMoveToNext(list);
|
||||
i++;
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
printf("\nREMOVING\n");
|
||||
|
||||
ListMoveToHead(list);
|
||||
for (int i = 0; i < 7; i++) {
|
||||
Date* aux = ListRemoveCurrent(list);
|
||||
free(aux);
|
||||
ListMoveToNext(list);
|
||||
ListTestInvariants(list);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
size = ListGetSize(list);
|
||||
ListMove(list, 0);
|
||||
while (i < size) {
|
||||
Date* p = (Date*)ListGetCurrentItem(list);
|
||||
printf("%s\n", DateFormat(p, DMY));
|
||||
ListMoveToNext(list);
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
#include "Date.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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));
|
||||
Date* d = (Date*)malloc(sizeof(*d));
|
||||
if (d == NULL) return d;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
// Compare dates a and b.
|
||||
// Return an integer >0 if a>b, 0 if a==b and <0 if a<b.
|
||||
int DateCompare(const Date* a, const Date* b) {
|
||||
int r = (int)a->year - (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); // d must precede MAX!
|
||||
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 = 1;
|
||||
d->year++;
|
||||
}
|
||||
}
|
||||
assert(invariant(d)); // check invariant
|
||||
}
|
||||
|
||||
// Decrement date.
|
||||
// Precondition: d must succeed DateMIN.
|
||||
void DateDecr(Date* d) {
|
||||
assert(DateCompare(d, &DateMIN) > 0); // d must succeed MIN!
|
||||
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
|
||||
}
|
||||
|
||||
// static char* monthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
|
||||
// "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
static char strBuffer[64];
|
||||
|
||||
static char* fmts[] = {
|
||||
(char*)"%04d-%02d-%02d", // YMD
|
||||
(char*)"%3$02d/%2$02d/%1$04d", // DMY
|
||||
(char*)"%2$02d/%3$02d/%1$04d", // MDY
|
||||
};
|
||||
|
||||
// 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 acording to format and return NEW Date,
|
||||
// or NULL if invalid or memory error.
|
||||
Date* DateParse(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;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef _DATE_
|
||||
#define _DATE_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
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) ;
|
||||
int DateCompare(const Date* a, const Date* b) ;
|
||||
void DateIncr(Date* d) ;
|
||||
void DateDecr(Date* d) ;
|
||||
char* DateFormat(const Date* d, int FMT) ;
|
||||
Date* DateParse(const char* str, int FMT) ;
|
||||
|
||||
#endif //_DATE_
|
|
@ -0,0 +1,338 @@
|
|||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// SORTED LIST implementation based on a linked list
|
||||
//
|
||||
|
||||
// ***************** COMPLETAR AS FUNCOES !!! *******************
|
||||
|
||||
#include "SortedList.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// 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_
|
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Integers Binary Tree --- FIRST VERSION --- Test Code
|
||||
//
|
||||
// SOME FUNCTIONS ARE INCOMPLETE on IntegersBinTree.c
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "IntegersBinTree.h"
|
||||
|
||||
void printInteger(int* p) { printf("%d ", *p); }
|
||||
|
||||
void multiplyIntegerBy2(int* p) { *p *= 2; }
|
||||
|
||||
int main(void) {
|
||||
Tree* tree = createExampleTree();
|
||||
|
||||
printf("Created an example tree\n");
|
||||
|
||||
if (TreeIsEmpty(tree)) {
|
||||
printf("The created tree is EMPTY\n");
|
||||
} else {
|
||||
printf("The created tree is OK\n");
|
||||
}
|
||||
|
||||
printf("Number of nodes = %d\n", TreeGetNumberOfNodes(tree));
|
||||
|
||||
printf("Height = %d\n", TreeGetHeight(tree));
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
TreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal : ");
|
||||
|
||||
TreeTraverseINOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("POST-Order traversal : ");
|
||||
|
||||
TreeTraverseInPOSTOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (TreeContains(tree, i)) {
|
||||
printf("The tree contains %d\n", i);
|
||||
} else {
|
||||
printf("The tree DOES NOT CONTAIN %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Multiply each value by 2\n");
|
||||
|
||||
TreeTraverseInPREOrder(tree, multiplyIntegerBy2);
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
TreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (TreeEquals(tree, tree)) {
|
||||
printf("The tree EQUALS ITSELF\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
if (TreeMirrors(tree, tree)) {
|
||||
printf("Something WRONG happened!!\n");
|
||||
} else {
|
||||
printf("The tree DOES NOT MIRROR ITSELF\n");
|
||||
}
|
||||
|
||||
TreeDestroy(&tree);
|
||||
|
||||
printf("The tree was DESTROYED\n");
|
||||
|
||||
if (TreeIsEmpty(tree)) {
|
||||
printf("The tree is NOW EMPTY\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from an old example (2003, 2020)
|
||||
//
|
||||
// Integers Binary Tree --- FIRST VERSION --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include "IntegersBinTree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _TreeNode {
|
||||
ItemType item;
|
||||
struct _TreeNode* left;
|
||||
struct _TreeNode* right;
|
||||
};
|
||||
|
||||
Tree* TreeCreate(void) { return NULL; }
|
||||
|
||||
void TreeDestroy(Tree** pRoot) {
|
||||
// ...
|
||||
}
|
||||
|
||||
int TreeIsEmpty(const Tree* root) { return root == NULL; }
|
||||
|
||||
int TreeEquals(const Tree* root1, const Tree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeMirrors(const Tree* root1, const Tree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeGetNumberOfNodes(const Tree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeGetHeight(const Tree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TreeTraverseInPREOrder(Tree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void TreeTraverseINOrder(Tree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void TreeTraverseInPOSTOrder(Tree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
int TreeContains(const Tree* root, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeAdd(Tree** pRoot, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeRemove(Tree** pRoot, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
Tree* createExampleTree(void) {
|
||||
// SHOULD NEVER BE DONE LIKE THIS !!!???!!!
|
||||
|
||||
int numNodes = 8;
|
||||
|
||||
Tree* nodes[numNodes];
|
||||
|
||||
for (int i = 0; i < numNodes; i++) {
|
||||
nodes[i] = (Tree*)malloc(sizeof(Tree));
|
||||
nodes[i]->item = i + 1;
|
||||
nodes[i]->left = nodes[i]->right = NULL;
|
||||
}
|
||||
|
||||
nodes[3]->left = nodes[7];
|
||||
|
||||
nodes[1]->left = nodes[3];
|
||||
nodes[1]->right = nodes[4];
|
||||
|
||||
nodes[2]->left = nodes[5];
|
||||
nodes[2]->right = nodes[6];
|
||||
|
||||
nodes[0]->left = nodes[1];
|
||||
nodes[0]->right = nodes[2];
|
||||
|
||||
return nodes[0];
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from an old example (2003, 2020)
|
||||
//
|
||||
// Integers Binary Tree --- FIRST VERSION --- INCOMPLETE
|
||||
//
|
||||
|
||||
#ifndef _INTEGERS_BINTREE_
|
||||
#define _INTEGERS_BINTREE_
|
||||
|
||||
// JUST storing integers
|
||||
typedef int ItemType;
|
||||
|
||||
typedef struct _TreeNode Tree;
|
||||
|
||||
Tree* TreeCreate(void);
|
||||
|
||||
void TreeDestroy(Tree** pRoot);
|
||||
|
||||
// Tree properties
|
||||
|
||||
int TreeIsEmpty(const Tree* root);
|
||||
|
||||
int TreeEquals(const Tree* root1, const Tree* root2);
|
||||
|
||||
int TreeMirrors(const Tree* root1, const Tree* root2);
|
||||
|
||||
// ...
|
||||
|
||||
// Getters
|
||||
|
||||
int TreeGetNumberOfNodes(const Tree* root);
|
||||
|
||||
int TreeGetHeight(const Tree* root);
|
||||
|
||||
ItemType TreeGetMin(const Tree* root);
|
||||
|
||||
ItemType TreeGetMax(const Tree* root);
|
||||
|
||||
Tree* TreeGetPointerToMinNode(const Tree* root);
|
||||
|
||||
Tree* TreeGetPointerToMaxNode(const Tree* root);
|
||||
|
||||
// ...
|
||||
|
||||
// Traversals
|
||||
|
||||
void TreeTraverseInPREOrder(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
void TreeTraverseINOrder(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
void TreeTraverseInPOSTOrder(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
// ...
|
||||
|
||||
// Operations with items
|
||||
|
||||
int TreeContains(const Tree* root, const ItemType item);
|
||||
|
||||
int TreeAdd(Tree** pRoot, const ItemType item);
|
||||
|
||||
int TreeRemove(Tree** pRoot, const ItemType item);
|
||||
|
||||
// ...
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
Tree* createExampleTree(void);
|
||||
|
||||
#endif // _INTEGERS_BINTREE_
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Integers Binary Tree --- SECOND VERSION --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "IntegersBinTree.h"
|
||||
|
||||
void printInteger(int* p) { printf("%d ", *p); }
|
||||
|
||||
void multiplyIntegerBy2(int* p) { *p *= 2; }
|
||||
|
||||
int main(void) {
|
||||
Tree* tree = createExampleTree();
|
||||
|
||||
printf("Created an example tree\n");
|
||||
|
||||
if (TreeIsEmpty(tree)) {
|
||||
printf("The created tree is EMPTY\n");
|
||||
} else {
|
||||
printf("The created tree is OK\n");
|
||||
}
|
||||
|
||||
printf("Number of nodes = %d\n", TreeGetNumberOfNodes(tree));
|
||||
|
||||
printf("Height = %d\n", TreeGetHeight(tree));
|
||||
|
||||
printf("SMALLEST value = %d\n", TreeGetMin(tree));
|
||||
|
||||
printf("LARGEST value = %d\n", TreeGetMax(tree));
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
TreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal : ");
|
||||
|
||||
TreeTraverseINOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("POST-Order traversal : ");
|
||||
|
||||
TreeTraverseInPOSTOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("LEVEL-by-LEVEL traversal using a QUEUE: ");
|
||||
|
||||
TreeTraverseLevelByLevelWithQUEUE(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("PRE-Order traversal using a STACK : ");
|
||||
|
||||
TreeTraverseInPREOrderWithSTACK(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal using a STACK: ");
|
||||
|
||||
TreeTraverseINOrderWithSTACK(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (TreeContains(tree, i)) {
|
||||
printf("The tree contains %d\n", i);
|
||||
} else {
|
||||
printf("The tree DOES NOT CONTAIN %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Multiply each value by 2\n");
|
||||
|
||||
TreeTraverseInPREOrder(tree, multiplyIntegerBy2);
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
TreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (TreeEquals(tree, tree)) {
|
||||
printf("The tree EQUALS ITSELF\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
if (TreeMirrors(tree, tree)) {
|
||||
printf("Something WRONG happened!!\n");
|
||||
} else {
|
||||
printf("The tree DOES NOT MIRROR ITSELF\n");
|
||||
}
|
||||
|
||||
printf("STORING in a file\n");
|
||||
|
||||
TreeStoreInFile(tree, "arvore1.txt", 1);
|
||||
|
||||
printf("READING from a file\n");
|
||||
|
||||
Tree* treeFromFile = TreeGetFromFile("arvore1.txt", 1);
|
||||
|
||||
printf("FINISHED READING from a file\n");
|
||||
|
||||
if (TreeEquals(tree, treeFromFile)) {
|
||||
printf("The tree EQUALS the one read from file\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
TreeDestroy(&tree);
|
||||
|
||||
printf("The tree was DESTROYED\n");
|
||||
|
||||
if (TreeIsEmpty(tree)) {
|
||||
printf("The tree is NOW EMPTY\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from an old example...
|
||||
//
|
||||
// Integers Binary Tree --- SECOND VERSION --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include "IntegersBinTree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersQueue.h"
|
||||
#include "PointersStack.h"
|
||||
|
||||
struct _TreeNode {
|
||||
ItemType item;
|
||||
struct _TreeNode* left;
|
||||
struct _TreeNode* right;
|
||||
};
|
||||
|
||||
Tree* TreeCreate(void) { return NULL; }
|
||||
|
||||
void TreeDestroy(Tree** pRoot) {
|
||||
// ...
|
||||
}
|
||||
|
||||
int TreeIsEmpty(const Tree* root) { return root == NULL; }
|
||||
|
||||
int TreeEquals(const Tree* root1, const Tree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeMirrors(const Tree* root1, const Tree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeGetNumberOfNodes(const Tree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeGetHeight(const Tree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeGetMin(const Tree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeGetMax(const Tree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TreeTraverseInPREOrder(Tree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void TreeTraverseINOrder(Tree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void TreeTraverseInPOSTOrder(Tree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void TreeTraverseLevelByLevelWithQUEUE(Tree* root,
|
||||
void (*function)(ItemType* p)) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not checking for queue errors !!
|
||||
// Create the QUEUE for storing POINTERS
|
||||
|
||||
Queue* queue = QueueCreate();
|
||||
|
||||
QueueEnqueue(queue, root);
|
||||
|
||||
while (QueueIsEmpty(queue) == 0) {
|
||||
Tree* p = QueueDequeue(queue);
|
||||
|
||||
function(&(p->item));
|
||||
|
||||
if (p->left != NULL) {
|
||||
QueueEnqueue(queue, p->left);
|
||||
}
|
||||
if (p->right != NULL) {
|
||||
QueueEnqueue(queue, p->right);
|
||||
}
|
||||
}
|
||||
|
||||
QueueDestroy(&queue);
|
||||
}
|
||||
|
||||
void TreeTraverseInPREOrderWithSTACK(Tree* root,
|
||||
void (*function)(ItemType* p)) {}
|
||||
|
||||
void TreeTraverseINOrderWithSTACK(Tree* root, void (*function)(ItemType* p)) {}
|
||||
|
||||
// ...
|
||||
|
||||
int TreeContains(const Tree* root, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeAdd(Tree** pRoot, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreeRemove(Tree** pRoot, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
// Storing and reading from a FILE
|
||||
|
||||
struct _fileNode {
|
||||
ItemType item;
|
||||
int emptyLeftSubTree;
|
||||
int emptyRightSubTree;
|
||||
};
|
||||
|
||||
static void _storeInFile(const Tree* root, FILE* f, int fileType) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct _fileNode r;
|
||||
r.item = root->item;
|
||||
r.emptyLeftSubTree = (root->left == NULL);
|
||||
r.emptyRightSubTree = (root->right == NULL);
|
||||
|
||||
if (fileType == 1) {
|
||||
fprintf(f, "%d %d %d ", r.item, r.emptyLeftSubTree, r.emptyRightSubTree);
|
||||
} else {
|
||||
fwrite(&r, sizeof(struct _fileNode), 1, f);
|
||||
}
|
||||
|
||||
_storeInFile(root->left, f, fileType);
|
||||
_storeInFile(root->right, f, fileType);
|
||||
}
|
||||
|
||||
static void _getFromFile(Tree** pRoot, FILE* f, int fileType) {
|
||||
struct _fileNode r;
|
||||
|
||||
if (fileType == 1) {
|
||||
fscanf(f, "%d", &r.item);
|
||||
fscanf(f, "%d", &r.emptyLeftSubTree);
|
||||
fscanf(f, "%d", &r.emptyRightSubTree);
|
||||
} else {
|
||||
fread(&r, sizeof(struct _fileNode), 1, f);
|
||||
}
|
||||
|
||||
Tree* newNode = (Tree*)malloc(sizeof(struct _TreeNode));
|
||||
|
||||
newNode->item = r.item;
|
||||
|
||||
if (r.emptyLeftSubTree) {
|
||||
newNode->left = NULL;
|
||||
} else {
|
||||
_getFromFile(&(newNode->left), f, fileType);
|
||||
}
|
||||
|
||||
if (r.emptyRightSubTree) {
|
||||
newNode->right = NULL;
|
||||
} else {
|
||||
_getFromFile(&(newNode->right), f, fileType);
|
||||
}
|
||||
|
||||
*pRoot = newNode;
|
||||
}
|
||||
|
||||
int TreeStoreInFile(const Tree* root, char* fileName, int fileType) {
|
||||
FILE* f = fopen(fileName, "w");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_storeInFile(root, f, fileType);
|
||||
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Tree* TreeGetFromFile(char* fileName, int fileType) {
|
||||
FILE* f = fopen(fileName, "r");
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Tree* root;
|
||||
_getFromFile(&root, f, fileType);
|
||||
|
||||
fclose(f);
|
||||
return root;
|
||||
}
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
Tree* createExampleTree(void) {
|
||||
// SHOULD NEVER BE DONE LIKE THIS !!!???!!!
|
||||
|
||||
int numNodes = 8;
|
||||
|
||||
Tree* nodes[numNodes];
|
||||
|
||||
for (int i = 0; i < numNodes; i++) {
|
||||
nodes[i] = (Tree*)malloc(sizeof(Tree));
|
||||
nodes[i]->item = i + 1;
|
||||
nodes[i]->left = nodes[i]->right = NULL;
|
||||
}
|
||||
|
||||
nodes[3]->left = nodes[7];
|
||||
|
||||
nodes[1]->left = nodes[3];
|
||||
nodes[1]->right = nodes[4];
|
||||
|
||||
nodes[2]->left = nodes[5];
|
||||
nodes[2]->right = nodes[6];
|
||||
|
||||
nodes[0]->left = nodes[1];
|
||||
nodes[0]->right = nodes[2];
|
||||
|
||||
return nodes[0];
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from an old example...
|
||||
//
|
||||
// Integers Binary Tree --- SECOND VERSION --- INCOMPLETE
|
||||
//
|
||||
|
||||
#ifndef _INTEGERS_BINTREE_
|
||||
#define _INTEGERS_BINTREE_
|
||||
|
||||
// JUST storing integers
|
||||
typedef int ItemType;
|
||||
|
||||
static int NO_ITEM = -999;
|
||||
|
||||
typedef struct _TreeNode Tree;
|
||||
|
||||
Tree* TreeCreate(void);
|
||||
|
||||
void TreeDestroy(Tree** pRoot);
|
||||
|
||||
// Tree properties
|
||||
|
||||
int TreeIsEmpty(const Tree* root);
|
||||
|
||||
int TreeEquals(const Tree* root1, const Tree* root2);
|
||||
|
||||
int TreeMirrors(const Tree* root1, const Tree* root2);
|
||||
|
||||
// ...
|
||||
|
||||
// Getters
|
||||
|
||||
int TreeGetNumberOfNodes(const Tree* root);
|
||||
|
||||
int TreeGetHeight(const Tree* root);
|
||||
|
||||
ItemType TreeGetMin(const Tree* root);
|
||||
|
||||
ItemType TreeGetMax(const Tree* root);
|
||||
|
||||
Tree* TreeGetPointerToMinNode(const Tree* root);
|
||||
|
||||
Tree* TreeGetPointerToMaxNode(const Tree* root);
|
||||
|
||||
// ...
|
||||
|
||||
// Recursive Traversals
|
||||
|
||||
void TreeTraverseInPREOrder(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
void TreeTraverseINOrder(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
void TreeTraverseInPOSTOrder(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
// Traversals using a QUEUE or STACK
|
||||
|
||||
void TreeTraverseLevelByLevelWithQUEUE(Tree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
void TreeTraverseInPREOrderWithSTACK(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
void TreeTraverseINOrderWithSTACK(Tree* root, void (*function)(ItemType* p));
|
||||
|
||||
// ...
|
||||
|
||||
// Operations with items
|
||||
|
||||
int TreeContains(const Tree* root, const ItemType item);
|
||||
|
||||
int TreeAdd(Tree** pRoot, const ItemType item);
|
||||
|
||||
int TreeRemove(Tree** pRoot, const ItemType item);
|
||||
|
||||
// ...
|
||||
|
||||
// Storing and reading from a FILE
|
||||
|
||||
int TreeStoreInFile(const Tree* root, char* fileName, int fileType);
|
||||
|
||||
Tree* TreeGetFromFile(char* fileName, int fileType);
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
Tree* createExampleTree(void);
|
||||
|
||||
Tree* createAnotherExampleTree(void);
|
||||
|
||||
#endif // _INTEGERS_BINTREE_
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersQueueNode {
|
||||
void* data;
|
||||
struct _PointersQueueNode* next;
|
||||
};
|
||||
|
||||
struct _PointersQueue {
|
||||
int size; // current Queue size
|
||||
struct _PointersQueueNode* head; // the head of the Queue
|
||||
struct _PointersQueueNode* tail; // the tail of the Queue
|
||||
};
|
||||
|
||||
Queue* QueueCreate(void) {
|
||||
Queue* q = (Queue*)malloc(sizeof(Queue));
|
||||
assert(q != NULL);
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
return q;
|
||||
}
|
||||
|
||||
void QueueDestroy(Queue** p) {
|
||||
assert(*p != NULL);
|
||||
Queue* q = *p;
|
||||
|
||||
QueueClear(q);
|
||||
|
||||
free(q);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void QueueClear(Queue* q) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* p = q->head;
|
||||
struct _PointersQueueNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
int QueueSize(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return q->size;
|
||||
}
|
||||
|
||||
int QueueIsEmpty(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return (q->size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* QueuePeek(const Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
return q->head->data;
|
||||
}
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* aux;
|
||||
aux = (struct _PointersQueueNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = NULL;
|
||||
|
||||
q->size++;
|
||||
|
||||
if (q->size == 1) {
|
||||
q->head = aux;
|
||||
q->tail = aux;
|
||||
} else {
|
||||
q->tail->next = aux;
|
||||
q->tail = aux;
|
||||
}
|
||||
}
|
||||
|
||||
void* QueueDequeue(Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
|
||||
struct _PointersQueueNode* aux = q->head;
|
||||
void* p = aux->data;
|
||||
|
||||
q->size--;
|
||||
|
||||
if (q->size == 0) {
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
} else {
|
||||
q->head = aux->next;
|
||||
}
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_QUEUE_
|
||||
|
||||
#define _POINTERS_QUEUE_
|
||||
|
||||
typedef struct _PointersQueue Queue;
|
||||
|
||||
Queue* QueueCreate(void);
|
||||
|
||||
void QueueDestroy(Queue** p);
|
||||
|
||||
void QueueClear(Queue* q);
|
||||
|
||||
int QueueSize(const Queue* q);
|
||||
|
||||
int QueueIsEmpty(const Queue* q);
|
||||
|
||||
void* QueuePeek(const Queue* q);
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p);
|
||||
|
||||
void* QueueDequeue(Queue* q);
|
||||
|
||||
#endif // _POINTERS_QUEUE_
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersStack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersStackNode {
|
||||
void* data;
|
||||
struct _PointersStackNode* next;
|
||||
};
|
||||
|
||||
struct _PointersStack {
|
||||
int cur_size; // current stack size
|
||||
struct _PointersStackNode* top; // the node on the top of the stack
|
||||
};
|
||||
|
||||
Stack* StackCreate(void) {
|
||||
Stack* s = (Stack*)malloc(sizeof(Stack));
|
||||
assert(s != NULL);
|
||||
|
||||
s->cur_size = 0;
|
||||
s->top = NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
void StackDestroy(Stack** p) {
|
||||
assert(*p != NULL);
|
||||
Stack* s = *p;
|
||||
|
||||
StackClear(s);
|
||||
|
||||
free(s);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void StackClear(Stack* s) {
|
||||
assert(s != NULL);
|
||||
|
||||
struct _PointersStackNode* p = s->top;
|
||||
struct _PointersStackNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
s->cur_size = 0;
|
||||
s->top = NULL;
|
||||
}
|
||||
|
||||
int StackSize(const Stack* s) {
|
||||
assert(s != NULL);
|
||||
return s->cur_size;
|
||||
}
|
||||
|
||||
int StackIsEmpty(const Stack* s) {
|
||||
assert(s != NULL);
|
||||
return (s->cur_size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* StackPeek(const Stack* s) {
|
||||
assert(s != NULL && s->cur_size > 0);
|
||||
return s->top->data;
|
||||
}
|
||||
|
||||
void StackPush(Stack* s, void* p) {
|
||||
assert(s != NULL);
|
||||
|
||||
struct _PointersStackNode* aux;
|
||||
aux = (struct _PointersStackNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = s->top;
|
||||
|
||||
s->top = aux;
|
||||
|
||||
s->cur_size++;
|
||||
}
|
||||
|
||||
void* StackPop(Stack* s) {
|
||||
assert(s != NULL && s->cur_size > 0);
|
||||
|
||||
struct _PointersStackNode* aux = s->top;
|
||||
s->top = aux->next;
|
||||
s->cur_size--;
|
||||
|
||||
void* p = aux->data;
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_STACK_
|
||||
#define _POINTERS_STACK_
|
||||
|
||||
typedef struct _PointersStack Stack;
|
||||
|
||||
Stack* StackCreate(void);
|
||||
|
||||
void StackDestroy(Stack** p);
|
||||
|
||||
void StackClear(Stack* s);
|
||||
|
||||
int StackSize(const Stack* s);
|
||||
|
||||
int StackIsEmpty(const Stack* s);
|
||||
|
||||
void* StackPeek(const Stack* s);
|
||||
|
||||
void StackPush(Stack* s, void* p);
|
||||
|
||||
void* StackPop(Stack* s);
|
||||
|
||||
#endif // _POINTERS_STACK_
|
|
@ -0,0 +1,104 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Integers Binary Search Tree --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "BinarySearchTree.h"
|
||||
|
||||
void printInteger(int* p) { printf("%d ", *p); }
|
||||
|
||||
void multiplyIntegerBy2(int* p) { *p *= 2; }
|
||||
|
||||
int main(void) {
|
||||
BSTree* tree = createExampleBSTree(16);
|
||||
|
||||
if (BSTreeIsBST(tree)) {
|
||||
printf("Created an example BSTree\n");
|
||||
} else {
|
||||
printf("The created BSTree is NOT OK\n");
|
||||
}
|
||||
|
||||
if (BSTreeIsEmpty(tree)) {
|
||||
printf("The created BSTree is EMPTY\n");
|
||||
} else {
|
||||
printf("The created BSTree is OK\n");
|
||||
}
|
||||
|
||||
printf("Number of nodes = %d\n", BSTreeGetNumberOfNodes(tree));
|
||||
|
||||
printf("Height = %d\n", BSTreeGetHeight(tree));
|
||||
|
||||
printf("SMALLEST value = %d\n", BSTreeGetMin(tree));
|
||||
|
||||
printf("LARGEST value = %d\n", BSTreeGetMax(tree));
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
BSTreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal : ");
|
||||
|
||||
BSTreeTraverseINOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("POST-Order traversal : ");
|
||||
|
||||
BSTreeTraverseInPOSTOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("LEVEL-by-LEVEL traversal using a QUEUE: ");
|
||||
|
||||
BSTreeTraverseLevelByLevelWithQUEUE(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("REMOVING some elements\n");
|
||||
|
||||
for (int i = 0; i < 25; i++) {
|
||||
BSTreeRemove(&tree, i);
|
||||
}
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
BSTreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal : ");
|
||||
|
||||
BSTreeTraverseINOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("POST-Order traversal : ");
|
||||
|
||||
BSTreeTraverseInPOSTOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("LEVEL-by-LEVEL traversal using a QUEUE: ");
|
||||
|
||||
BSTreeTraverseLevelByLevelWithQUEUE(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
BSTreeDestroy(&tree);
|
||||
|
||||
printf("The BSTree was DESTROYED\n");
|
||||
|
||||
if (BSTreeIsEmpty(tree)) {
|
||||
printf("The BSTree is NOW EMPTY\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,375 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from an old example...
|
||||
//
|
||||
// Integers Binary Search Tree --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include "BinarySearchTree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersQueue.h"
|
||||
#include "PointersStack.h"
|
||||
|
||||
struct _BSTreeNode {
|
||||
ItemType item;
|
||||
struct _BSTreeNode* left;
|
||||
struct _BSTreeNode* right;
|
||||
};
|
||||
|
||||
BSTree* BSTreeCreate(void) { return NULL; }
|
||||
|
||||
void BSTreeDestroy(BSTree** pRoot) {
|
||||
// ...
|
||||
}
|
||||
|
||||
int BSTreeIsEmpty(const BSTree* root) { return root == NULL; }
|
||||
|
||||
//
|
||||
// NEW - Adapted from
|
||||
// https://www.geeksforgeeks.org/check-if-a-binary-tree-is-bst-simple-and-efficient-approach/
|
||||
//
|
||||
int _isBST(const BSTree* root, ItemType* prevItem) {
|
||||
if (root == NULL) {
|
||||
return 1;
|
||||
}
|
||||
// IN_ORDER TRAVERSAL
|
||||
if (_isBST(root->left, prevItem) == 0) {
|
||||
return 0;
|
||||
}
|
||||
// Allow only distinct valued nodes
|
||||
if (root->item <= *prevItem) {
|
||||
return 0;
|
||||
}
|
||||
// Update prevValue to current
|
||||
*prevItem = root->item;
|
||||
|
||||
return _isBST(root->right, prevItem);
|
||||
}
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
int BSTreeIsBST(const BSTree* root) {
|
||||
int prevItem = MIN_POSSIBLE;
|
||||
|
||||
return _isBST(root, &prevItem);
|
||||
}
|
||||
|
||||
int BSTreeEquals(const BSTree* root1, const BSTree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSTreeMirrors(const BSTree* root1, const BSTree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSTreeGetNumberOfNodes(const BSTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSTreeGetHeight(const BSTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSTreeGetMin(const BSTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BSTreeGetMax(const BSTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BSTreeTraverseInPREOrder(BSTree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void BSTreeTraverseINOrder(BSTree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void BSTreeTraverseInPOSTOrder(BSTree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void BSTreeTraverseLevelByLevelWithQUEUE(BSTree* root,
|
||||
void (*function)(ItemType* p)) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not checking for queue errors !!
|
||||
// Create the QUEUE for storing POINTERS
|
||||
|
||||
Queue* queue = QueueCreate();
|
||||
|
||||
QueueEnqueue(queue, root);
|
||||
|
||||
while (QueueIsEmpty(queue) == 0) {
|
||||
BSTree* p = QueueDequeue(queue);
|
||||
|
||||
function(&(p->item));
|
||||
|
||||
if (p->left != NULL) {
|
||||
QueueEnqueue(queue, p->left);
|
||||
}
|
||||
if (p->right != NULL) {
|
||||
QueueEnqueue(queue, p->right);
|
||||
}
|
||||
}
|
||||
|
||||
QueueDestroy(&queue);
|
||||
}
|
||||
|
||||
void BSTreeTraverseInPREOrderWithSTACK(BSTree* root,
|
||||
void (*function)(ItemType* p)) {}
|
||||
|
||||
void BSTreeTraverseINOrderWithSTACK(BSTree* root,
|
||||
void (*function)(ItemType* p)) {}
|
||||
|
||||
// ...
|
||||
|
||||
int BSTreeContains(const BSTree* root, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
int BSTreeAdd(BSTree** pRoot, const ItemType item) {
|
||||
BSTree* root = *pRoot;
|
||||
|
||||
struct _BSTreeNode* new = (struct _BSTreeNode*)malloc(sizeof(*new));
|
||||
assert(new != NULL);
|
||||
|
||||
new->item = item;
|
||||
new->left = new->right = NULL;
|
||||
|
||||
if (root == NULL) {
|
||||
*pRoot = new;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct _BSTreeNode* prev = NULL;
|
||||
struct _BSTreeNode* current = root;
|
||||
|
||||
while (current != NULL) {
|
||||
if (current->item == item) {
|
||||
free(new);
|
||||
return 0;
|
||||
} // Not allowed
|
||||
|
||||
prev = current;
|
||||
if (current->item > item) {
|
||||
current = current->left;
|
||||
} else {
|
||||
current = current->right;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev->item > item) {
|
||||
prev->left = new;
|
||||
} else {
|
||||
prev->right = new;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
void _deleteNextNode(BSTree** pRoot, ItemType* pItem) {
|
||||
if ((*pRoot)->left == NULL) {
|
||||
// FOUND IT
|
||||
BSTree* auxPointer = *pRoot;
|
||||
|
||||
*pItem = auxPointer->item;
|
||||
|
||||
*pRoot = auxPointer->right;
|
||||
|
||||
free(auxPointer);
|
||||
} else {
|
||||
_deleteNextNode(&((*pRoot)->left), pItem);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
void _removeNode(BSTree** pPointer) {
|
||||
BSTree* nodePointer = *pPointer;
|
||||
|
||||
if ((nodePointer->left == NULL) && (nodePointer->right == NULL)) {
|
||||
/* A LEAF node */
|
||||
|
||||
free(nodePointer);
|
||||
|
||||
*pPointer = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodePointer->left == NULL) {
|
||||
/* It has only a RIGHT sub-tree */
|
||||
|
||||
*pPointer = nodePointer->right;
|
||||
|
||||
free(nodePointer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodePointer->right == NULL) {
|
||||
/* It has only a LEFT sub-tree */
|
||||
|
||||
*pPointer = nodePointer->left;
|
||||
|
||||
free(nodePointer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Node has TWO CHILDREN */
|
||||
/* Replace its item with the item of the next node in-order */
|
||||
/* And remove that node */
|
||||
|
||||
_deleteNextNode(&(nodePointer->right), &(nodePointer->item));
|
||||
}
|
||||
|
||||
//
|
||||
// NEW - Search for the node and remove it
|
||||
// with the help an auxiliary function
|
||||
//
|
||||
int BSTreeRemove(BSTree** pRoot, const ItemType item) {
|
||||
BSTree* root = *pRoot;
|
||||
|
||||
if (root == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (root->item == item) {
|
||||
_removeNode(pRoot);
|
||||
return 1;
|
||||
}
|
||||
if (root->item > item) {
|
||||
return BSTreeRemove(&(root->left), item);
|
||||
}
|
||||
|
||||
return BSTreeRemove(&(root->right), item);
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
// Storing and reading from a FILE
|
||||
|
||||
struct _fileNode {
|
||||
ItemType item;
|
||||
int emptyLeftSubBSTree;
|
||||
int emptyRightSubBSTree;
|
||||
};
|
||||
|
||||
static void _storeInFile(const BSTree* root, FILE* f, int fileType) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct _fileNode r;
|
||||
r.item = root->item;
|
||||
r.emptyLeftSubBSTree = (root->left == NULL);
|
||||
r.emptyRightSubBSTree = (root->right == NULL);
|
||||
|
||||
if (fileType == 1) {
|
||||
fprintf(f, "%d %d %d ", r.item, r.emptyLeftSubBSTree,
|
||||
r.emptyRightSubBSTree);
|
||||
} else {
|
||||
fwrite(&r, sizeof(struct _fileNode), 1, f);
|
||||
}
|
||||
|
||||
_storeInFile(root->left, f, fileType);
|
||||
_storeInFile(root->right, f, fileType);
|
||||
}
|
||||
|
||||
static void _getFromFile(BSTree** pRoot, FILE* f, int fileType) {
|
||||
struct _fileNode r;
|
||||
|
||||
if (fileType == 1) {
|
||||
fscanf(f, "%d", &r.item);
|
||||
fscanf(f, "%d", &r.emptyLeftSubBSTree);
|
||||
fscanf(f, "%d", &r.emptyRightSubBSTree);
|
||||
} else {
|
||||
fread(&r, sizeof(struct _fileNode), 1, f);
|
||||
}
|
||||
|
||||
BSTree* newNode = (BSTree*)malloc(sizeof(struct _BSTreeNode));
|
||||
|
||||
newNode->item = r.item;
|
||||
|
||||
if (r.emptyLeftSubBSTree) {
|
||||
newNode->left = NULL;
|
||||
} else {
|
||||
_getFromFile(&(newNode->left), f, fileType);
|
||||
}
|
||||
|
||||
if (r.emptyRightSubBSTree) {
|
||||
newNode->right = NULL;
|
||||
} else {
|
||||
_getFromFile(&(newNode->right), f, fileType);
|
||||
}
|
||||
|
||||
*pRoot = newNode;
|
||||
}
|
||||
|
||||
int BSTreeStoreInFile(const BSTree* root, char* fileName, int fileType) {
|
||||
FILE* f = fopen(fileName, "w");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_storeInFile(root, f, fileType);
|
||||
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
BSTree* BSTreeGetFromFile(char* fileName, int fileType) {
|
||||
FILE* f = fopen(fileName, "r");
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BSTree* root;
|
||||
_getFromFile(&root, f, fileType);
|
||||
|
||||
fclose(f);
|
||||
return root;
|
||||
}
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
//
|
||||
// TO DO : change to BST
|
||||
//
|
||||
BSTree* createExampleBSTree(unsigned int n) {
|
||||
int numNodes = 20;
|
||||
|
||||
BSTree* root = BSTreeCreate();
|
||||
|
||||
for (int i = 10; i < numNodes; i += 2) {
|
||||
BSTreeAdd(&root, 2 * i + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numNodes; i += 2) {
|
||||
BSTreeAdd(&root, 2 * i);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from an old example...
|
||||
//
|
||||
// Integers Binary Search Tree --- INCOMPLETE
|
||||
//
|
||||
|
||||
#ifndef _BINARY_SEARCH_Tree_
|
||||
#define _BINARY_SEARCH_Tree_
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// JUST storing integers
|
||||
typedef int ItemType;
|
||||
|
||||
static int NO_ITEM = INT_MAX;
|
||||
|
||||
static int MIN_POSSIBLE = INT_MIN;
|
||||
|
||||
typedef struct _BSTreeNode BSTree;
|
||||
|
||||
BSTree* BSTreeCreate(void);
|
||||
|
||||
void BSTreeDestroy(BSTree** pRoot);
|
||||
|
||||
// BSTree properties
|
||||
|
||||
int BSTreeIsEmpty(const BSTree* root);
|
||||
|
||||
int BSTreeIsBST(const BSTree* root);
|
||||
|
||||
int BSTreeEquals(const BSTree* root1, const BSTree* root2);
|
||||
|
||||
int BSTreeMirrors(const BSTree* root1, const BSTree* root2);
|
||||
|
||||
// ...
|
||||
|
||||
// Getters
|
||||
|
||||
int BSTreeGetNumberOfNodes(const BSTree* root);
|
||||
|
||||
int BSTreeGetHeight(const BSTree* root);
|
||||
|
||||
ItemType BSTreeGetMin(const BSTree* root);
|
||||
|
||||
ItemType BSTreeGetMax(const BSTree* root);
|
||||
|
||||
BSTree* BSTreeGetPointerToMinNode(const BSTree* root);
|
||||
|
||||
BSTree* BSTreeGetPointerToMaxNode(const BSTree* root);
|
||||
|
||||
// ...
|
||||
|
||||
// Recursive Traversals
|
||||
|
||||
void BSTreeTraverseInPREOrder(BSTree* root, void (*function)(ItemType* p));
|
||||
|
||||
void BSTreeTraverseINOrder(BSTree* root, void (*function)(ItemType* p));
|
||||
|
||||
void BSTreeTraverseInPOSTOrder(BSTree* root, void (*function)(ItemType* p));
|
||||
|
||||
// Traversals using a QUEUE or STACK
|
||||
|
||||
void BSTreeTraverseLevelByLevelWithQUEUE(BSTree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
void BSTreeTraverseInPREOrderWithSTACK(BSTree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
void BSTreeTraverseINOrderWithSTACK(BSTree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
// ...
|
||||
|
||||
// Operations with items
|
||||
|
||||
int BSTreeContains(const BSTree* root, const ItemType item);
|
||||
|
||||
int BSTreeAdd(BSTree** pRoot, const ItemType item);
|
||||
|
||||
int BSTreeRemove(BSTree** pRoot, const ItemType item);
|
||||
|
||||
// ...
|
||||
|
||||
// Storing and reading from a FILE
|
||||
|
||||
int BSTreeStoreInFile(const BSTree* root, char* fileName, int fileType);
|
||||
|
||||
BSTree* BSTreeGetFromFile(char* fileName, int fileType);
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
BSTree* createExampleBSTree(unsigned int n);
|
||||
|
||||
BSTree* createAnotherExampleBSTree(void);
|
||||
|
||||
#endif // _BINARY_SEARCH_Tree_
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersQueueNode {
|
||||
void* data;
|
||||
struct _PointersQueueNode* next;
|
||||
};
|
||||
|
||||
struct _PointersQueue {
|
||||
int size; // current Queue size
|
||||
struct _PointersQueueNode* head; // the head of the Queue
|
||||
struct _PointersQueueNode* tail; // the tail of the Queue
|
||||
};
|
||||
|
||||
Queue* QueueCreate(void) {
|
||||
Queue* q = (Queue*)malloc(sizeof(Queue));
|
||||
assert(q != NULL);
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
return q;
|
||||
}
|
||||
|
||||
void QueueDestroy(Queue** p) {
|
||||
assert(*p != NULL);
|
||||
Queue* q = *p;
|
||||
|
||||
QueueClear(q);
|
||||
|
||||
free(q);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void QueueClear(Queue* q) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* p = q->head;
|
||||
struct _PointersQueueNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
int QueueSize(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return q->size;
|
||||
}
|
||||
|
||||
int QueueIsEmpty(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return (q->size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* QueuePeek(const Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
return q->head->data;
|
||||
}
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* aux;
|
||||
aux = (struct _PointersQueueNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = NULL;
|
||||
|
||||
q->size++;
|
||||
|
||||
if (q->size == 1) {
|
||||
q->head = aux;
|
||||
q->tail = aux;
|
||||
} else {
|
||||
q->tail->next = aux;
|
||||
q->tail = aux;
|
||||
}
|
||||
}
|
||||
|
||||
void* QueueDequeue(Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
|
||||
struct _PointersQueueNode* aux = q->head;
|
||||
void* p = aux->data;
|
||||
|
||||
q->size--;
|
||||
|
||||
if (q->size == 0) {
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
} else {
|
||||
q->head = aux->next;
|
||||
}
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_QUEUE_
|
||||
|
||||
#define _POINTERS_QUEUE_
|
||||
|
||||
typedef struct _PointersQueue Queue;
|
||||
|
||||
Queue* QueueCreate(void);
|
||||
|
||||
void QueueDestroy(Queue** p);
|
||||
|
||||
void QueueClear(Queue* q);
|
||||
|
||||
int QueueSize(const Queue* q);
|
||||
|
||||
int QueueIsEmpty(const Queue* q);
|
||||
|
||||
void* QueuePeek(const Queue* q);
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p);
|
||||
|
||||
void* QueueDequeue(Queue* q);
|
||||
|
||||
#endif // _POINTERS_QUEUE_
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersStack.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersStackNode {
|
||||
void* data;
|
||||
struct _PointersStackNode* next;
|
||||
};
|
||||
|
||||
struct _PointersStack {
|
||||
int cur_size; // current stack size
|
||||
struct _PointersStackNode* top; // the node on the top of the stack
|
||||
};
|
||||
|
||||
Stack* StackCreate(void) {
|
||||
Stack* s = (Stack*)malloc(sizeof(Stack));
|
||||
assert(s != NULL);
|
||||
|
||||
s->cur_size = 0;
|
||||
s->top = NULL;
|
||||
return s;
|
||||
}
|
||||
|
||||
void StackDestroy(Stack** p) {
|
||||
assert(*p != NULL);
|
||||
Stack* s = *p;
|
||||
|
||||
StackClear(s);
|
||||
|
||||
free(s);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void StackClear(Stack* s) {
|
||||
assert(s != NULL);
|
||||
|
||||
struct _PointersStackNode* p = s->top;
|
||||
struct _PointersStackNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
s->cur_size = 0;
|
||||
s->top = NULL;
|
||||
}
|
||||
|
||||
int StackSize(const Stack* s) {
|
||||
assert(s != NULL);
|
||||
return s->cur_size;
|
||||
}
|
||||
|
||||
int StackIsEmpty(const Stack* s) {
|
||||
assert(s != NULL);
|
||||
return (s->cur_size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* StackPeek(const Stack* s) {
|
||||
assert(s != NULL && s->cur_size > 0);
|
||||
return s->top->data;
|
||||
}
|
||||
|
||||
void StackPush(Stack* s, void* p) {
|
||||
assert(s != NULL);
|
||||
|
||||
struct _PointersStackNode* aux;
|
||||
aux = (struct _PointersStackNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = s->top;
|
||||
|
||||
s->top = aux;
|
||||
|
||||
s->cur_size++;
|
||||
}
|
||||
|
||||
void* StackPop(Stack* s) {
|
||||
assert(s != NULL && s->cur_size > 0);
|
||||
|
||||
struct _PointersStackNode* aux = s->top;
|
||||
s->top = aux->next;
|
||||
s->cur_size--;
|
||||
|
||||
void* p = aux->data;
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Joaquim Madeira, Algoritmos e Estruturas de Dados, November 2023
|
||||
//
|
||||
// Pointers stack (First In Last Out) implementation based on a linked list
|
||||
//
|
||||
|
||||
#ifndef _POINTERS_STACK_
|
||||
#define _POINTERS_STACK_
|
||||
|
||||
typedef struct _PointersStack Stack;
|
||||
|
||||
Stack* StackCreate(void);
|
||||
|
||||
void StackDestroy(Stack** p);
|
||||
|
||||
void StackClear(Stack* s);
|
||||
|
||||
int StackSize(const Stack* s);
|
||||
|
||||
int StackIsEmpty(const Stack* s);
|
||||
|
||||
void* StackPeek(const Stack* s);
|
||||
|
||||
void StackPush(Stack* s, void* p);
|
||||
|
||||
void* StackPop(Stack* s);
|
||||
|
||||
#endif // _POINTERS_STACK_
|
Binary file not shown.
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// Joaquim Madeira, May 2020
|
||||
//
|
||||
// Integers AVL Tree --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "AVLTree.h"
|
||||
|
||||
void printInteger(int* p) { printf("%d ", *p); }
|
||||
|
||||
void printIntegerForTreeDisplay(int* p) { printf("%d ", *p); }
|
||||
|
||||
void multiplyIntegerBy2(int* p) { *p *= 2; }
|
||||
|
||||
int main(void) {
|
||||
AVLTree* tree = createExampleAVLTree(16);
|
||||
|
||||
if (AVLTreeIsBST(tree)) {
|
||||
printf("Created an example AVLTree that is a BST\n");
|
||||
} else {
|
||||
printf("The created AVLTree is NOT a BST\n");
|
||||
}
|
||||
|
||||
if (AVLTreeIsEmpty(tree)) {
|
||||
printf("The created AVLTree is EMPTY\n");
|
||||
} else {
|
||||
printf("The created AVLTree is OK\n");
|
||||
}
|
||||
|
||||
printf("Number of nodes = %d\n", AVLTreeGetNumberOfNodes(tree));
|
||||
|
||||
printf("Height = %d\n", AVLTreeGetHeight(tree));
|
||||
|
||||
printf("SMALLEST value = %d\n", AVLTreeGetMin(tree));
|
||||
|
||||
printf("LARGEST value = %d\n", AVLTreeGetMax(tree));
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
AVLTreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal : ");
|
||||
|
||||
AVLTreeTraverseINOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("POST-Order traversal : ");
|
||||
|
||||
AVLTreeTraverseInPOSTOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("LEVEL-by-LEVEL traversal using a QUEUE: ");
|
||||
|
||||
AVLTreeTraverseLevelByLevelWithQUEUE(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
AVLTreeDisplay(tree, printIntegerForTreeDisplay);
|
||||
|
||||
printf("REMOVING some elements\n");
|
||||
|
||||
for (int i = 0; i < 25; i++) {
|
||||
AVLTreeRemove(&tree, i);
|
||||
}
|
||||
|
||||
printf("PRE-Order traversal : ");
|
||||
|
||||
AVLTreeTraverseInPREOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("IN-Order traversal : ");
|
||||
|
||||
AVLTreeTraverseINOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("POST-Order traversal : ");
|
||||
|
||||
AVLTreeTraverseInPOSTOrder(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("LEVEL-by-LEVEL traversal using a QUEUE: ");
|
||||
|
||||
AVLTreeTraverseLevelByLevelWithQUEUE(tree, printInteger);
|
||||
|
||||
printf("\n");
|
||||
|
||||
AVLTreeDestroy(&tree);
|
||||
|
||||
printf("The AVLTree was DESTROYED\n");
|
||||
|
||||
if (AVLTreeIsEmpty(tree)) {
|
||||
printf("The AVLTree is NOW EMPTY\n");
|
||||
} else {
|
||||
printf("Something WRONG happened!!\n");
|
||||
}
|
||||
|
||||
printf("Inserting the natural numbers:\n");
|
||||
|
||||
for (int i = 1; i < 13; i++) {
|
||||
AVLTreeAdd(&tree, i);
|
||||
printf("--\n");
|
||||
AVLTreeDisplay(tree, printIntegerForTreeDisplay);
|
||||
printf("--\n");
|
||||
}
|
||||
|
||||
AVLTreeStoreInFile(tree, "arvore.txt", 1);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,510 @@
|
|||
//
|
||||
// Joaquim Madeira, May 2020
|
||||
//
|
||||
// Integers AVL Tree --- INCOMPLETE
|
||||
//
|
||||
|
||||
#include "AVLTree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "PointersQueue.h"
|
||||
#include "PointersStack.h"
|
||||
|
||||
struct _AVLTreeNode {
|
||||
ItemType item;
|
||||
struct _AVLTreeNode* left;
|
||||
struct _AVLTreeNode* right;
|
||||
int height;
|
||||
};
|
||||
|
||||
AVLTree* AVLTreeCreate(void) { return NULL; }
|
||||
|
||||
void AVLTreeDestroy(AVLTree** pRoot) {
|
||||
// ...
|
||||
}
|
||||
|
||||
int AVLTreeIsEmpty(const AVLTree* root) { return root == NULL; }
|
||||
|
||||
//
|
||||
// NEW - Adapted from
|
||||
// https://www.geeksforgeeks.org/check-if-a-binary-tree-is-bst-simple-and-efficient-approach/
|
||||
//
|
||||
int _isBST(const AVLTree* root, ItemType* prevItem) {
|
||||
if (root == NULL) {
|
||||
return 1;
|
||||
}
|
||||
// IN_ORDER TRAVERSAL
|
||||
if (_isBST(root->left, prevItem) == 0) {
|
||||
return 0;
|
||||
}
|
||||
// Allow only distinct valued nodes
|
||||
if (root->item <= *prevItem) {
|
||||
return 0;
|
||||
}
|
||||
// Update prevValue to current
|
||||
*prevItem = root->item;
|
||||
|
||||
return _isBST(root->right, prevItem);
|
||||
}
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
int AVLTreeIsBST(const AVLTree* root) {
|
||||
int prevItem = MIN_POSSIBLE;
|
||||
|
||||
return _isBST(root, &prevItem);
|
||||
}
|
||||
|
||||
int AVLTreeEquals(const AVLTree* root1, const AVLTree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVLTreeMirrors(const AVLTree* root1, const AVLTree* root2) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVLTreeGetNumberOfNodes(const AVLTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
int AVLTreeGetHeight(const AVLTree* root) {
|
||||
if (root == NULL) return -1;
|
||||
|
||||
return root->height;
|
||||
}
|
||||
|
||||
int AVLTreeGetMin(const AVLTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVLTreeGetMax(const AVLTree* root) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVLTreeTraverseInPREOrder(AVLTree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void AVLTreeTraverseINOrder(AVLTree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void AVLTreeTraverseInPOSTOrder(AVLTree* root, void (*function)(ItemType* p)) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void AVLTreeTraverseLevelByLevelWithQUEUE(AVLTree* root,
|
||||
void (*function)(ItemType* p)) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not checking for queue errors !!
|
||||
// Create the QUEUE for storing POINTERS
|
||||
|
||||
Queue* queue = QueueCreate();
|
||||
|
||||
QueueEnqueue(queue, root);
|
||||
|
||||
while (QueueIsEmpty(queue) == 0) {
|
||||
AVLTree* p = QueueDequeue(queue);
|
||||
|
||||
function(&(p->item));
|
||||
|
||||
if (p->left != NULL) {
|
||||
QueueEnqueue(queue, p->left);
|
||||
}
|
||||
if (p->right != NULL) {
|
||||
QueueEnqueue(queue, p->right);
|
||||
}
|
||||
}
|
||||
|
||||
QueueDestroy(&queue);
|
||||
}
|
||||
|
||||
void AVLTreeTraverseInPREOrderWithSTACK(AVLTree* root,
|
||||
void (*function)(ItemType* p)) {}
|
||||
|
||||
void AVLTreeTraverseINOrderWithSTACK(AVLTree* root,
|
||||
void (*function)(ItemType* p)) {}
|
||||
|
||||
// ...
|
||||
|
||||
int AVLTreeContains(const AVLTree* root, const ItemType item) {
|
||||
// ...
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Auxiliary functions for tree balancing
|
||||
|
||||
static void _updateNodeHeight(AVLTree* t) {
|
||||
assert(t != NULL);
|
||||
|
||||
int leftHeight = AVLTreeGetHeight(t->left);
|
||||
|
||||
int rightHeight = AVLTreeGetHeight(t->right);
|
||||
|
||||
if (leftHeight >= rightHeight) {
|
||||
t->height = leftHeight + 1;
|
||||
} else {
|
||||
t->height = rightHeight + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void _singleRotateWithLeftChild(AVLTree** p) {
|
||||
AVLTree* pLeft = (*p)->left;
|
||||
|
||||
(*p)->left = pLeft->right;
|
||||
pLeft->right = *p;
|
||||
|
||||
_updateNodeHeight(*p);
|
||||
_updateNodeHeight(pLeft);
|
||||
|
||||
*p = pLeft;
|
||||
}
|
||||
|
||||
static void _singleRotateWithRightChild(AVLTree** p) {
|
||||
AVLTree* pRight = (*p)->right;
|
||||
|
||||
(*p)->right = pRight->left;
|
||||
pRight->left = *p;
|
||||
|
||||
_updateNodeHeight(*p);
|
||||
_updateNodeHeight(pRight);
|
||||
|
||||
*p = pRight;
|
||||
}
|
||||
|
||||
static void _doubleRotateWithLeftChild(AVLTree** p) {
|
||||
_singleRotateWithRightChild(&(*p)->left);
|
||||
_singleRotateWithLeftChild(p);
|
||||
}
|
||||
|
||||
static void _doubleRotateWithRightChild(AVLTree** p) {
|
||||
_singleRotateWithLeftChild(&(*p)->right);
|
||||
_singleRotateWithRightChild(p);
|
||||
}
|
||||
|
||||
static void _balanceNode(AVLTree** pRoot) {
|
||||
int leftHeight, rightHeight;
|
||||
|
||||
if (*pRoot == NULL) return;
|
||||
leftHeight = AVLTreeGetHeight((*pRoot)->left);
|
||||
rightHeight = AVLTreeGetHeight((*pRoot)->right);
|
||||
|
||||
if (leftHeight - rightHeight == 2) {
|
||||
leftHeight = AVLTreeGetHeight((*pRoot)->left->left);
|
||||
rightHeight = AVLTreeGetHeight((*pRoot)->left->right);
|
||||
if (leftHeight >= rightHeight)
|
||||
_singleRotateWithLeftChild(pRoot);
|
||||
else
|
||||
_doubleRotateWithLeftChild(pRoot);
|
||||
} else if (rightHeight - leftHeight == 2) {
|
||||
rightHeight = AVLTreeGetHeight((*pRoot)->right->right);
|
||||
leftHeight = AVLTreeGetHeight((*pRoot)->right->left);
|
||||
if (rightHeight >= leftHeight)
|
||||
_singleRotateWithRightChild(pRoot);
|
||||
else
|
||||
_doubleRotateWithRightChild(pRoot);
|
||||
} else
|
||||
(*pRoot)->height =
|
||||
leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
int AVLTreeAdd(AVLTree** pRoot, const ItemType item) {
|
||||
AVLTree* root = *pRoot;
|
||||
|
||||
if (root == NULL) {
|
||||
root = (struct _AVLTreeNode*)malloc(sizeof(*root));
|
||||
assert(root != NULL);
|
||||
|
||||
root->item = item;
|
||||
root->left = root->right = NULL;
|
||||
root->height = 0;
|
||||
|
||||
*pRoot = root;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (item < root->item) {
|
||||
// Try to insert on the left
|
||||
if (AVLTreeAdd(&(root->left), item) == 0) {
|
||||
// No success
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unbalanced on the left ?
|
||||
if (AVLTreeGetHeight(root->left) - AVLTreeGetHeight(root->right) == 2) {
|
||||
if (item < root->left->item) {
|
||||
_singleRotateWithLeftChild(pRoot);
|
||||
} else {
|
||||
_doubleRotateWithLeftChild(pRoot);
|
||||
}
|
||||
}
|
||||
_updateNodeHeight(root);
|
||||
return 1;
|
||||
} else if (item > root->item) {
|
||||
// Try to insert on the right
|
||||
if (AVLTreeAdd(&(root->right), item) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unbalanced on the right ?
|
||||
if (AVLTreeGetHeight(root->right) - AVLTreeGetHeight(root->left) == 2) {
|
||||
if (item > root->right->item) {
|
||||
_singleRotateWithRightChild(pRoot);
|
||||
} else {
|
||||
_doubleRotateWithRightChild(pRoot);
|
||||
}
|
||||
}
|
||||
_updateNodeHeight(root);
|
||||
return 1;
|
||||
} else {
|
||||
// Not allowed
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
void _deleteNextNode(AVLTree** pRoot, ItemType* pItem) {
|
||||
if ((*pRoot)->left == NULL) {
|
||||
// FOUND IT
|
||||
AVLTree* auxPointer = *pRoot;
|
||||
|
||||
*pItem = auxPointer->item;
|
||||
|
||||
*pRoot = auxPointer->right;
|
||||
|
||||
free(auxPointer);
|
||||
} else {
|
||||
_deleteNextNode(&((*pRoot)->left), pItem);
|
||||
|
||||
_updateNodeHeight(*pRoot);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// NEW
|
||||
//
|
||||
void _removeNode(AVLTree** pPointer) {
|
||||
AVLTree* nodePointer = *pPointer;
|
||||
|
||||
if ((nodePointer->left == NULL) && (nodePointer->right == NULL)) {
|
||||
/* A LEAF node */
|
||||
|
||||
free(nodePointer);
|
||||
|
||||
*pPointer = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodePointer->left == NULL) {
|
||||
/* It has only a RIGHT sub-tree */
|
||||
|
||||
*pPointer = nodePointer->right;
|
||||
|
||||
free(nodePointer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodePointer->right == NULL) {
|
||||
/* It has only a LEFT sub-tree */
|
||||
|
||||
*pPointer = nodePointer->left;
|
||||
|
||||
free(nodePointer);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Node has TWO CHILDREN */
|
||||
/* Replace its item with the item of the next node in-order */
|
||||
/* And remove that node */
|
||||
|
||||
_deleteNextNode(&(nodePointer->right), &(nodePointer->item));
|
||||
}
|
||||
|
||||
//
|
||||
// NEW - Search for the node and remove it
|
||||
// with the help an auxiliary function
|
||||
//
|
||||
int AVLTreeRemove(AVLTree** pRoot, const ItemType item) {
|
||||
AVLTree* root = *pRoot;
|
||||
|
||||
if (root == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (root->item == item) {
|
||||
_removeNode(pRoot);
|
||||
_balanceNode(pRoot); // Balance at this node
|
||||
return 1;
|
||||
}
|
||||
if (root->item > item) {
|
||||
int result = AVLTreeRemove(&(root->left), item);
|
||||
if (result) {
|
||||
_balanceNode(pRoot); // Balance at this node
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int result = AVLTreeRemove(&(root->right), item);
|
||||
if (result) {
|
||||
_balanceNode(pRoot); // Balance at this node
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
// DISPLAYING on the console
|
||||
|
||||
static void _displayTree(const AVLTree* root, unsigned int level,
|
||||
void (*printFunc)(ItemType* p)) {
|
||||
unsigned int i;
|
||||
|
||||
if (root == NULL) {
|
||||
for (i = 0; i <= level; i++) printf("\t");
|
||||
printf("*\n");
|
||||
return;
|
||||
}
|
||||
|
||||
_displayTree(root->right, level + 1, printFunc);
|
||||
|
||||
for (i = 0; i <= level; i++) printf("\t");
|
||||
|
||||
printf("%d\n", root->item);
|
||||
|
||||
_displayTree(root->left, level + 1, printFunc);
|
||||
}
|
||||
|
||||
void AVLTreeDisplay(const AVLTree* root, void (*printFunc)(ItemType* p)) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
_displayTree(root, 0, printFunc);
|
||||
}
|
||||
|
||||
// Storing and reading from a FILE
|
||||
|
||||
struct _fileNode {
|
||||
ItemType item;
|
||||
int emptyLeftSubAVLTree;
|
||||
int emptyRightSubAVLTree;
|
||||
int nodeHeight;
|
||||
};
|
||||
|
||||
static void _storeInFile(const AVLTree* root, FILE* f, int fileType) {
|
||||
if (root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct _fileNode r;
|
||||
r.item = root->item;
|
||||
r.emptyLeftSubAVLTree = (root->left == NULL);
|
||||
r.emptyRightSubAVLTree = (root->right == NULL);
|
||||
r.nodeHeight = root->height;
|
||||
|
||||
if (fileType == 1) {
|
||||
fprintf(f, "%d %d %d %d ", r.item, r.nodeHeight, r.emptyLeftSubAVLTree,
|
||||
r.emptyRightSubAVLTree);
|
||||
} else {
|
||||
fwrite(&r, sizeof(struct _fileNode), 1, f);
|
||||
}
|
||||
|
||||
_storeInFile(root->left, f, fileType);
|
||||
_storeInFile(root->right, f, fileType);
|
||||
}
|
||||
|
||||
static void _getFromFile(AVLTree** pRoot, FILE* f, int fileType) {
|
||||
struct _fileNode r;
|
||||
|
||||
if (fileType == 1) {
|
||||
fscanf(f, "%d", &r.item);
|
||||
fscanf(f, "%d", &r.emptyLeftSubAVLTree);
|
||||
fscanf(f, "%d", &r.emptyRightSubAVLTree);
|
||||
fscanf(f, "%d", &r.nodeHeight);
|
||||
} else {
|
||||
fread(&r, sizeof(struct _fileNode), 1, f);
|
||||
}
|
||||
|
||||
AVLTree* newNode = (AVLTree*)malloc(sizeof(struct _AVLTreeNode));
|
||||
|
||||
newNode->item = r.item;
|
||||
newNode->height = r.nodeHeight;
|
||||
|
||||
if (r.emptyLeftSubAVLTree) {
|
||||
newNode->left = NULL;
|
||||
} else {
|
||||
_getFromFile(&(newNode->left), f, fileType);
|
||||
}
|
||||
|
||||
if (r.emptyRightSubAVLTree) {
|
||||
newNode->right = NULL;
|
||||
} else {
|
||||
_getFromFile(&(newNode->right), f, fileType);
|
||||
}
|
||||
|
||||
*pRoot = newNode;
|
||||
}
|
||||
|
||||
int AVLTreeStoreInFile(const AVLTree* root, char* fileName, int fileType) {
|
||||
FILE* f = fopen(fileName, "w");
|
||||
if (f == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_storeInFile(root, f, fileType);
|
||||
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
AVLTree* AVLTreeGetFromFile(char* fileName, int fileType) {
|
||||
FILE* f = fopen(fileName, "r");
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AVLTree* root;
|
||||
_getFromFile(&root, f, fileType);
|
||||
|
||||
fclose(f);
|
||||
return root;
|
||||
}
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
AVLTree* createExampleAVLTree(unsigned int n) {
|
||||
int numNodes = 20;
|
||||
|
||||
AVLTree* root = AVLTreeCreate();
|
||||
|
||||
for (int i = 10; i < numNodes; i += 2) {
|
||||
AVLTreeAdd(&root, 2 * i + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numNodes; i += 2) {
|
||||
AVLTreeAdd(&root, 2 * i);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Joaquim Madeira, May 2020
|
||||
//
|
||||
// Integers AVL Tree --- INCOMPLETE
|
||||
//
|
||||
|
||||
#ifndef _AVL_Tree_
|
||||
#define _AVL_Tree_
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// JUST storing integers
|
||||
typedef int ItemType;
|
||||
|
||||
static int NO_ITEM = INT_MAX;
|
||||
|
||||
static int MIN_POSSIBLE = INT_MIN;
|
||||
|
||||
typedef struct _AVLTreeNode AVLTree;
|
||||
|
||||
AVLTree* AVLTreeCreate(void);
|
||||
|
||||
void AVLTreeDestroy(AVLTree** pRoot);
|
||||
|
||||
// AVLTree properties
|
||||
|
||||
int AVLTreeIsEmpty(const AVLTree* root);
|
||||
|
||||
int AVLTreeIsBST(const AVLTree* root);
|
||||
|
||||
int AVLTreeEquals(const AVLTree* root1, const AVLTree* root2);
|
||||
|
||||
int AVLTreeMirrors(const AVLTree* root1, const AVLTree* root2);
|
||||
|
||||
// ...
|
||||
|
||||
// Getters
|
||||
|
||||
int AVLTreeGetNumberOfNodes(const AVLTree* root);
|
||||
|
||||
int AVLTreeGetHeight(const AVLTree* root);
|
||||
|
||||
ItemType AVLTreeGetMin(const AVLTree* root);
|
||||
|
||||
ItemType AVLTreeGetMax(const AVLTree* root);
|
||||
|
||||
AVLTree* AVLTreeGetPointerToMinNode(const AVLTree* root);
|
||||
|
||||
AVLTree* AVLTreeGetPointerToMaxNode(const AVLTree* root);
|
||||
|
||||
// ...
|
||||
|
||||
// Recursive Traversals
|
||||
|
||||
void AVLTreeTraverseInPREOrder(AVLTree* root, void (*function)(ItemType* p));
|
||||
|
||||
void AVLTreeTraverseINOrder(AVLTree* root, void (*function)(ItemType* p));
|
||||
|
||||
void AVLTreeTraverseInPOSTOrder(AVLTree* root, void (*function)(ItemType* p));
|
||||
|
||||
// Traversals using a QUEUE or STACK
|
||||
|
||||
void AVLTreeTraverseLevelByLevelWithQUEUE(AVLTree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
void AVLTreeTraverseInPREOrderWithSTACK(AVLTree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
void AVLTreeTraverseINOrderWithSTACK(AVLTree* root,
|
||||
void (*function)(ItemType* p));
|
||||
|
||||
// ...
|
||||
|
||||
// Operations with items
|
||||
|
||||
int AVLTreeContains(const AVLTree* root, const ItemType item);
|
||||
|
||||
int AVLTreeAdd(AVLTree** pRoot, const ItemType item);
|
||||
|
||||
int AVLTreeRemove(AVLTree** pRoot, const ItemType item);
|
||||
|
||||
// ...
|
||||
|
||||
// DISPLAYING on the console
|
||||
|
||||
void AVLTreeDisplay(const AVLTree* root, void (*printFunc)(ItemType* p));
|
||||
|
||||
// Storing and reading from a FILE
|
||||
|
||||
int AVLTreeStoreInFile(const AVLTree* root, char* fileName, int fileType);
|
||||
|
||||
AVLTree* AVLTreeGetFromFile(char* fileName, int fileType);
|
||||
|
||||
// JUST FOR RUNNING EXAMPLES - REMOVE FROM THE INTERFACE
|
||||
|
||||
AVLTree* createExampleAVLTree(unsigned int n);
|
||||
|
||||
AVLTree* createAnotherExampleAVLTree(void);
|
||||
|
||||
#endif // _AVL_Tree_
|
|
@ -0,0 +1,117 @@
|
|||
//
|
||||
// Joaquim Madeira, April 2020
|
||||
//
|
||||
// Adapted from Tomás Oliveira e Silva, AED, September 2015
|
||||
//
|
||||
// Pointers queue (First In First Out) implementation based on an array
|
||||
// of pointers
|
||||
//
|
||||
|
||||
#include "PointersQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct _PointersQueueNode {
|
||||
void* data;
|
||||
struct _PointersQueueNode* next;
|
||||
};
|
||||
|
||||
struct _PointersQueue {
|
||||
int size; // current Queue size
|
||||
struct _PointersQueueNode* head; // the head of the Queue
|
||||
struct _PointersQueueNode* tail; // the tail of the Queue
|
||||
};
|
||||
|
||||
Queue* QueueCreate(void) {
|
||||
Queue* q = (Queue*)malloc(sizeof(Queue));
|
||||
assert(q != NULL);
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
return q;
|
||||
}
|
||||
|
||||
void QueueDestroy(Queue** p) {
|
||||
assert(*p != NULL);
|
||||
Queue* q = *p;
|
||||
|
||||
QueueClear(q);
|
||||
|
||||
free(q);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
void QueueClear(Queue* q) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* p = q->head;
|
||||
struct _PointersQueueNode* aux;
|
||||
|
||||
while (p != NULL) {
|
||||
aux = p;
|
||||
p = aux->next;
|
||||
free(aux);
|
||||
}
|
||||
|
||||
q->size = 0;
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
}
|
||||
|
||||
int QueueSize(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return q->size;
|
||||
}
|
||||
|
||||
int QueueIsEmpty(const Queue* q) {
|
||||
assert(q != NULL);
|
||||
return (q->size == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void* QueuePeek(const Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
return q->head->data;
|
||||
}
|
||||
|
||||
void QueueEnqueue(Queue* q, void* p) {
|
||||
assert(q != NULL);
|
||||
|
||||
struct _PointersQueueNode* aux;
|
||||
aux = (struct _PointersQueueNode*)malloc(sizeof(*aux));
|
||||
assert(aux != NULL);
|
||||
|
||||
aux->data = p;
|
||||
aux->next = NULL;
|
||||
|
||||
q->size++;
|
||||
|
||||
if (q->size == 1) {
|
||||
q->head = aux;
|
||||
q->tail = aux;
|
||||
} else {
|
||||
q->tail->next = aux;
|
||||
q->tail = aux;
|
||||
}
|
||||
}
|
||||
|
||||
void* QueueDequeue(Queue* q) {
|
||||
assert(q != NULL && q->size > 0);
|
||||
|
||||
struct _PointersQueueNode* aux = q->head;
|
||||
void* p = aux->data;
|
||||
|
||||
q->size--;
|
||||
|
||||
if (q->size == 0) {
|
||||
q->head = NULL;
|
||||
q->tail = NULL;
|
||||
} else {
|
||||
q->head = aux->next;
|
||||
}
|
||||
|
||||
free(aux);
|
||||
|
||||
return p;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue