[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
|
# Config files
|
||||||
/**/*.iml
|
/**/*.iml
|
||||||
|
|
||||||
|
# Data files
|
||||||
|
/**/*.dat
|
||||||
|
|
||||||
# Output/Cache files
|
# Output/Cache files
|
||||||
/**/out/
|
/**/out/
|
||||||
/**/__pycache__/
|
/**/__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