Skip to content
Snippets Groups Projects
Commit 621400cb authored by Manuel Bucher's avatar Manuel Bucher
Browse files

Refractored Array und List

parent 97a3c65f
Branches
No related merge requests found
......@@ -3,7 +3,7 @@ all: loesung
WARNINGS = -Wall #-Werror
OPTIONAL = -Wextra -Wpedantic -Wshadow
DEBUG = -g -ggdb -fno-omit-frame-pointer
OPTIMIZE = -O2 -std=c11
OPTIMIZE = -Og -std=c11
loesung: Makefile loesung.c
$(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung.c
......
......@@ -7,13 +7,30 @@
typedef struct Tile {
uint32_t x;
uint32_t y;
struct Tile *p_n; // north, used for initial list
struct Tile *p_next; // used for list
struct Tile *p_n; // north
struct Tile *p_e; // east
struct Tile *p_s; // south
struct Tile *p_w; // west
} Tile;
// Reservieren und initialisieren des Speicherplatz eines Tiles
Tile* tile_new() {
Tile *p_tile = malloc(sizeof(Tile));
if(p_tile == NULL) { // failed to allocate memory
return NULL;
}
p_tile->x = 0;
p_tile->y = 0;
p_tile->p_next = NULL;
p_tile->p_n = NULL;
p_tile->p_e = NULL;
p_tile->p_s = NULL;
p_tile->p_w = NULL;
return p_tile;
}
int tile_compare(const void *p, const void *q) {
const Tile *s = *(const Tile**) p;
const Tile *t = *(const Tile**) q;
......@@ -35,62 +52,73 @@ int tile_compare(const void *p, const void *q) {
/** List von Tiles */
typedef struct List {
Tile *p_top;
uint32_t size;
uint32_t num_tiles;
uint32_t num_odd; // #ungerade Felder (`x - y` ist ungerade)
Tile max;
Tile min;
} List;
/** Initialisieren einer leeren Liste */
void list_init(List *s) {
s->p_top = NULL;
s->size = 0;
void list_init(List *this) {
this->p_top = NULL;
this->num_tiles = 0;
this->num_odd = 0;
this->min.x = UINT32_MAX;
this->min.y = UINT32_MAX;
this->max.x = 0;
this->max.y = 0;
}
/** Hinzufuegen eines leeren Elementes zur Liste
/** Min-Max funktionen fuer uint32_t */
inline uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
inline uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
/** Hinzufuegen von einem Tile zur Liste
*
* Voraussetzung: Die Liste muss initialisiert sein.
* Rueckgabe: Hinzugefuegtes, initialisiertes Tile
*/
Tile* list_push(List *s) {
Tile *p_tile = malloc(sizeof(Tile));
if(p_tile == NULL) { // failed to allocate memory
return NULL;
}
p_tile->x = 0;
p_tile->y = 0;
p_tile->p_n = s->p_top;
p_tile->p_e = NULL;
p_tile->p_s = NULL;
p_tile->p_w = NULL;
s->p_top = p_tile;
s->size++;
return p_tile;
}
/** Entfernen des obersten Elementes von der Liste und zurueckgeben des Tiles
*
* Der List muss mindestens ein Element besitzen
*/
Tile* list_pop(List *s) {
Tile *p_tile = s->p_top;
s->p_top = s->p_top->p_n;
s->size--;
return p_tile;
void list_push(List *this, Tile *p_tile) {
p_tile->p_next = this->p_top;
this->p_top = p_tile;
// Reichweite der Liste ermitteln
this->min.x = min(this->min.x, p_tile->x);
this->min.y = min(this->min.y, p_tile->y);
this->max.x = max(this->max.x, p_tile->x);
this->max.y = max(this->max.x, p_tile->y);
this->num_tiles++;
this->num_odd += (p_tile->x - p_tile->y)&1;
}
/** Freigeben des reservierten Speichers von der Liste
*
* Alle Tiles weReaden mit free vom speicher deallocaiert
* Alle Tiles mit free vom Speicher freigeben
*/
void list_free(List *s) {
Tile *p_cur = s->p_top;
s->p_top = NULL;
void list_free(List *this) {
Tile *p_cur = this->p_top;
this->p_top = NULL;
while (p_cur != NULL) {
Tile *p_next = p_cur->p_n;
Tile *p_next = p_cur->p_next;
free(p_cur);
p_cur = p_next;
}
}
/** pruefen, ob genausoviele gerade und ungerade Kacheln existieren,
* ohne einen Overflow zu erzeugen
* notwendiges Kriterium fuer unzusammenhaengender graph und hinreichendes
* fuer zusammenhaengender
*/
bool list_possible(List *this) {
return this->num_tiles - this->num_odd == this->num_odd;
}
/** Zurueckgeben, ob graph ein vollstaendiges Rechteck ist */
bool list_rectangle(List *this) {
return (this->max.x - this->min.x) * (this->max.y - this->min.y)
== this->num_tiles; // TODO: check for overflow?
}
typedef enum ReadResult {
ReadOk,
ReadEof,
......@@ -100,16 +128,6 @@ typedef enum ReadResult {
ReadErrTooManyNumbers,
ReadErrOutOfMemory,
} ReadResult;
typedef struct Field {
Tile t_min;
Tile t_max;
List tile_list;
Tile* (*tile_array);
uint32_t num_tiles;
} Field; // TODO: entfernen dieses Structs und nutzen von kleineren Strukturen:
// list + tile_array
/** Parsen einer Kachel(Tile) aus einer Zeile von StdIn
*
* Die Zahlen weReaden in das uebergebene Struct pTile geschrieben, sind aber
......@@ -135,16 +153,14 @@ ReadResult read_line(Tile* p_tile){
cur_whitespace = false;
cur_number++;
}
// 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wiRead ein
// 429496730 = 2^32 / 10, daher wenn `p_cur` groesser ist, wird ein
// overflow erzeugt
if (*p_cur > 429496729) {
printf("Multiplizieren ueberlauf %u\n", *p_cur);
return ReadErrIntegerOverflow;
}
(*p_cur) *= 10;
int digit = c - '0';
if (*p_cur > UINT32_MAX - digit) {
printf("Addieren ueberlauf %u\n", *p_cur);
return ReadErrIntegerOverflow;
}
(*p_cur) += digit;
......@@ -166,48 +182,15 @@ ReadResult read_line(Tile* p_tile){
return ReadOk;
}
/** Min-Max funktionen fuer uint32_t */
inline uint32_t min(uint32_t a, uint32_t b) { return a < b ? a : b; }
inline uint32_t max(uint32_t a, uint32_t b) { return a > b ? a : b; }
/** Initialisieren der Variablen im Feld
*
* Voraussetzung: Speicher vom Feld muss allocated sein.
*/
void field_init(Field *f) {
f->t_min.x = UINT32_MAX;
f->t_min.y = UINT32_MAX;
f->t_max.x = 0;
f->t_max.y = 0;
// initialisieren der Liste
list_init(&f->tile_list);
f->tile_array = 0;
f->num_tiles = 0;
}
/** Freigeben des im Heap reservierten speichers des fields f */
void field_drop(Field *f) {
uint32_t num_tiles = f->tile_list.size;
if(f->tile_array != NULL) {
for(uint32_t i = 0; i < num_tiles; i++) {
free(f->tile_array[i]);
}
free(f->tile_array);
} else {
list_free(&f->tile_list);
}
}
/** Liest das Input von StdIn und schreibt das Ergebnis in das uebergebene Feld
/** Liest das Input von StdIn und schreibt das Ergebnis in die uebergebene Liste
*
* Laufzeit: O(n)
* Speicherbedarf: O(n)
*
* Parameter:
* - Field* f pointer auf ein uninitialisiertes Feld, nach dem ausfuehren der
* Funktion ist das Feld initialisiert, wenn es sich um eine gueltige Eingabe
* handelt. `f->tile_list->size` Ist im Fehlerfall die Zeile, in dem die Eingabe
* ungueltig ist.
* - List* f ist ein Pointer auf eine initialisierte List, wird mit Eingabe
* gefuellt, im Fehlerfall ist die groesse `num_tiles` die Zeile, in welche
* der Fehler aufgetreten ist
*
* Return:
* - ReadResult:
......@@ -215,24 +198,21 @@ void field_drop(Field *f) {
* ReadErr..., falls die Eingabe ungueltig ist. `f` ist dann nicht vollstaendig
* initialisiert
*/
ReadResult field_init_tile_list(Field *f) {
ReadResult parse_input(List *this) {
while (1) {
Tile *t = list_push(&f->tile_list); // neues Element in die Liste einfuegen
if (t == NULL) {
Tile *p_tile = tile_new(); // neues Element erstellen
if (p_tile == NULL) {
return ReadErrOutOfMemory;
}
ReadResult result = read_line(t);
ReadResult result = read_line(p_tile);
switch (result) {
case ReadOk:
// Reichweite des Feldes ermitteln
f->t_min.x = min(f->t_min.x, t->x);
f->t_min.y = min(f->t_min.y, t->y);
f->t_max.x = max(f->t_max.x, t->x);
f->t_max.y = max(f->t_max.x, t->y);
// einfuegen in die Liste
list_push(this, p_tile);
break;
case ReadEof:
list_pop(&f->tile_list);
if (f->tile_list.size == 1) {
free(p_tile);
if (this->num_tiles == 0) {
return ReadEof;
} else {
return ReadOk;
......@@ -243,6 +223,24 @@ ReadResult field_init_tile_list(Field *f) {
}
}
/** Array in heap for accessing tiles in O(1)
*/
typedef struct Array {
uint32_t num_tiles;
Tile* (*tiles);
} Array;
/** Freigeben des im Heap reservierten Speichers des tile_arrays f
* inklusive der Tiles */
void array_drop(Array *this) {
if(this->tiles != NULL) {
for(uint32_t i = 0; i < this->num_tiles; i++) {
free(this->tiles[i]);
}
free(this->tiles);
}
}
typedef enum MallocResult {
MallocFailed,
MallocOk,
......@@ -251,18 +249,17 @@ typedef enum MallocResult {
*
* Laufzeit: O(n)
*/
MallocResult field_init_tile_array(Field *f) {
f->tile_array = malloc(f->tile_list.size * sizeof(Tile*));
if(f->tile_array == NULL) {
MallocResult array_from_list(Array *this, List* p_list) {
this->tiles = malloc(p_list->num_tiles * sizeof(Tile*));
if(this->tiles == NULL) {
return MallocFailed;
}
Tile *cur = f->tile_list.p_top;
f->num_tiles = f->tile_list.size;
for (uint32_t i = 0; i < f->tile_list.size; i++) {
f->tile_array[i] = cur;
cur = cur->p_n;
f->tile_array[i]->p_n = NULL;
this->num_tiles = p_list->num_tiles;
Tile *cur = p_list->p_top;
for (uint32_t i = 0; i < this->num_tiles; i++) {
this->tiles[i] = cur;
cur = cur->p_next;
this->tiles[i]->p_next = NULL;
}
return MallocOk;
}
......@@ -273,12 +270,12 @@ MallocResult field_init_tile_array(Field *f) {
* Rueckgabe: 0 falls alles ok
* 1 falls Dopplungen vorkommen TODO: enum
*/
int field_find_neighbours(Field *f) {
int array_find_neighbours(Array *this) {
uint32_t i = 0; // vergleich mit oberer Zeile
uint32_t begin_line = 0;
for (uint32_t j = 1; j < f->num_tiles; j++) {
Tile *p_cur = f->tile_array[j];
Tile *p_east = f->tile_array[j-1];
for (uint32_t j = 1; j < this->num_tiles; j++) {
Tile *p_cur = this->tiles[j];
Tile *p_east = this->tiles[j-1];
// ermitteln der ost/west-Beziehung
if (p_cur->y == p_east->y) {
if (p_cur->x == p_east->x) {
......@@ -292,14 +289,14 @@ int field_find_neighbours(Field *f) {
begin_line = i;
}
// ermitteln der nord/sued-Beziehung
Tile *p_north = f->tile_array[i];
Tile *p_north = this->tiles[i];
if (p_north->y < p_cur->y - 1) {
i = begin_line; // Luecke zwischen zeilen
} else if (p_north->y == p_cur->y - 1) {
// finden, ob paar existiert, zurzeit O(n).
// TODO: lohnt sich binaere suche mit O(log n)?
for(;f->tile_array[i]->y < p_cur->y && i < begin_line; i++);
p_north = f->tile_array[i];
for(;this->tiles[i]->y < p_cur->y && i < begin_line; i++);
p_north = this->tiles[i];
if (p_north->x == p_cur->x) {
p_north->p_s = p_cur;
p_cur->p_n = p_north;
......@@ -309,19 +306,19 @@ int field_find_neighbours(Field *f) {
return 0;
}
void field_print(Field *f) {
void array_print(Array *this) {
printf("# Array\n");
for (uint32_t i = 0; i < f->tile_list.size; i++) {
printf("%d %d\n", f->tile_array[i]->x, f->tile_array[i]->y);
for (uint32_t i = 0; i < this->num_tiles; i++) {
printf("%u %u\n", this->tiles[i]->x, this->tiles[i]->y);
}
}
int main (void)
{
// erstellen des main Objekt
Field field;
field_init(&field); // initialiseren der Variablen
ReadResult result = field_init_tile_list(&field); // lesen des Inputs
// erstellen des Liste zum parsen des inputs
List tile_list;
list_init(&tile_list); // Liste ist owner von Tiles
ReadResult result = parse_input(&tile_list); // lesen des Inputs
switch (result) {
case ReadOk:
break;
......@@ -329,44 +326,54 @@ int main (void)
// bei leerer Eingabe nichts ausgeben
return EXIT_SUCCESS;
case ReadErrIntegerOverflow:
fprintf(stderr, "Error in line %d: too big integer\n", field.tile_list.size);
field_drop(&field);
fprintf(stderr, "Error in line %d: too big integer\n", tile_list.num_tiles);
list_free(&tile_list);
return EXIT_FAILURE;
case ReadErrNonDigitCharacter:
fprintf(stderr, "Error in line %d: invalid character\n", field.tile_list.size);
field_drop(&field);
fprintf(stderr, "Error in line %d: invalid character\n", tile_list.num_tiles);
list_free(&tile_list);
return EXIT_FAILURE;
case ReadErrTooFewNumbers:
fprintf(stderr, "Error in line %d: Too few numbers, expected exactly 2\n",
field.tile_list.size);
field_drop(&field);
tile_list.num_tiles);
list_free(&tile_list);
return EXIT_FAILURE;
case ReadErrTooManyNumbers:
fprintf(stderr, "Error in line %d: Too much numbers, expected exactly 2\n",
field.tile_list.size);
field_drop(&field);
tile_list.num_tiles);
list_free(&tile_list);
return EXIT_FAILURE;
case ReadErrOutOfMemory:
fprintf(stderr, "Error in line %d: Failed to allocate more memory",
field.tile_list.size);
tile_list.num_tiles);
list_free(&tile_list);
return EXIT_FAILURE;
}
// turn the list into an array
if(field_init_tile_array(&field) == MallocFailed) {
Array tile_array;
// uebertragen der Liste in ein Array, und uebergeben des ownership der Tiles
// an das Array
if(array_from_list(&tile_array, &tile_list) == MallocFailed) {
fprintf(stderr, "Error: Failed to allocate enough memory");
list_free(&tile_list); // fehlgeschlagen, noch ist liste owner.
return EXIT_FAILURE;
}
qsort(field.tile_array, field.tile_list.size, sizeof(Tile*), tile_compare);
if(field_find_neighbours(&field)) {
// TODO: pruefen, ob notwendiges Kriterium erfuellt,
// TODO: Falls Rechteck, dieses Ausgeben.
//array_print(&tile_array);
qsort(tile_array.tiles, tile_array.num_tiles, sizeof(Tile*), tile_compare);
if(array_find_neighbours(&tile_array)) {
fprintf(stderr, "Error: Duplicated entry\n");
array_drop(&tile_array);
return EXIT_FAILURE;
}
//field_print(&field);
// TODO: Untertilesets finden
// TODO: Problem fuer die Untertilesets loesen
// TODO: Loesung ausgeben
// TODO: Pro Untertileset schauen ob notwendiges kriterium
// TODO: Loesung ausgeben (schwerer Teil)
field_drop(&field);
array_drop(&tile_array);
return EXIT_SUCCESS;
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment