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

Refractored Array und List

parent 97a3c65f
No related merge requests found
...@@ -3,7 +3,7 @@ all: loesung ...@@ -3,7 +3,7 @@ all: loesung
WARNINGS = -Wall #-Werror WARNINGS = -Wall #-Werror
OPTIONAL = -Wextra -Wpedantic -Wshadow OPTIONAL = -Wextra -Wpedantic -Wshadow
DEBUG = -g -ggdb -fno-omit-frame-pointer DEBUG = -g -ggdb -fno-omit-frame-pointer
OPTIMIZE = -O2 -std=c11 OPTIMIZE = -Og -std=c11
loesung: Makefile loesung.c loesung: Makefile loesung.c
$(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung.c $(CC) -o $@ $(WARNINGS) $(OPTIONAL) $(DEBUG) $(OPTIMIZE) loesung.c
......
...@@ -7,13 +7,30 @@ ...@@ -7,13 +7,30 @@
typedef struct Tile { typedef struct Tile {
uint32_t x; uint32_t x;
uint32_t y; 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_e; // east
struct Tile *p_s; // south struct Tile *p_s; // south
struct Tile *p_w; // west struct Tile *p_w; // west
} Tile; } 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) { int tile_compare(const void *p, const void *q) {
const Tile *s = *(const Tile**) p; const Tile *s = *(const Tile**) p;
const Tile *t = *(const Tile**) q; const Tile *t = *(const Tile**) q;
...@@ -35,62 +52,73 @@ int tile_compare(const void *p, const void *q) { ...@@ -35,62 +52,73 @@ int tile_compare(const void *p, const void *q) {
/** List von Tiles */ /** List von Tiles */
typedef struct List { typedef struct List {
Tile *p_top; 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; } List;
/** Initialisieren einer leeren Liste */ /** Initialisieren einer leeren Liste */
void list_init(List *s) { void list_init(List *this) {
s->p_top = NULL; this->p_top = NULL;
s->size = 0; 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. * Voraussetzung: Die Liste muss initialisiert sein.
* Rueckgabe: Hinzugefuegtes, initialisiertes Tile * Rueckgabe: Hinzugefuegtes, initialisiertes Tile
*/ */
Tile* list_push(List *s) { void list_push(List *this, Tile *p_tile) {
Tile *p_tile = malloc(sizeof(Tile)); p_tile->p_next = this->p_top;
if(p_tile == NULL) { // failed to allocate memory this->p_top = p_tile;
return NULL; // Reichweite der Liste ermitteln
} this->min.x = min(this->min.x, p_tile->x);
p_tile->x = 0; this->min.y = min(this->min.y, p_tile->y);
p_tile->y = 0; this->max.x = max(this->max.x, p_tile->x);
p_tile->p_n = s->p_top; this->max.y = max(this->max.x, p_tile->y);
p_tile->p_e = NULL; this->num_tiles++;
p_tile->p_s = NULL; this->num_odd += (p_tile->x - p_tile->y)&1;
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;
} }
/** Freigeben des reservierten Speichers von der Liste /** 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) { void list_free(List *this) {
Tile *p_cur = s->p_top; Tile *p_cur = this->p_top;
s->p_top = NULL; this->p_top = NULL;
while (p_cur != NULL) { while (p_cur != NULL) {
Tile *p_next = p_cur->p_n; Tile *p_next = p_cur->p_next;
free(p_cur); free(p_cur);
p_cur = p_next; 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 { typedef enum ReadResult {
ReadOk, ReadOk,
ReadEof, ReadEof,
...@@ -100,16 +128,6 @@ typedef enum ReadResult { ...@@ -100,16 +128,6 @@ typedef enum ReadResult {
ReadErrTooManyNumbers, ReadErrTooManyNumbers,
ReadErrOutOfMemory, ReadErrOutOfMemory,
} ReadResult; } 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 /** Parsen einer Kachel(Tile) aus einer Zeile von StdIn
* *
* Die Zahlen weReaden in das uebergebene Struct pTile geschrieben, sind aber * Die Zahlen weReaden in das uebergebene Struct pTile geschrieben, sind aber
...@@ -135,16 +153,14 @@ ReadResult read_line(Tile* p_tile){ ...@@ -135,16 +153,14 @@ ReadResult read_line(Tile* p_tile){
cur_whitespace = false; cur_whitespace = false;
cur_number++; 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 // overflow erzeugt
if (*p_cur > 429496729) { if (*p_cur > 429496729) {
printf("Multiplizieren ueberlauf %u\n", *p_cur);
return ReadErrIntegerOverflow; return ReadErrIntegerOverflow;
} }
(*p_cur) *= 10; (*p_cur) *= 10;
int digit = c - '0'; int digit = c - '0';
if (*p_cur > UINT32_MAX - digit) { if (*p_cur > UINT32_MAX - digit) {
printf("Addieren ueberlauf %u\n", *p_cur);
return ReadErrIntegerOverflow; return ReadErrIntegerOverflow;
} }
(*p_cur) += digit; (*p_cur) += digit;
...@@ -166,48 +182,15 @@ ReadResult read_line(Tile* p_tile){ ...@@ -166,48 +182,15 @@ ReadResult read_line(Tile* p_tile){
return ReadOk; return ReadOk;
} }
/** Min-Max funktionen fuer uint32_t */ /** Liest das Input von StdIn und schreibt das Ergebnis in die uebergebene Liste
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
* *
* Laufzeit: O(n) * Laufzeit: O(n)
* Speicherbedarf: O(n) * Speicherbedarf: O(n)
* *
* Parameter: * Parameter:
* - Field* f pointer auf ein uninitialisiertes Feld, nach dem ausfuehren der * - List* f ist ein Pointer auf eine initialisierte List, wird mit Eingabe
* Funktion ist das Feld initialisiert, wenn es sich um eine gueltige Eingabe * gefuellt, im Fehlerfall ist die groesse `num_tiles` die Zeile, in welche
* handelt. `f->tile_list->size` Ist im Fehlerfall die Zeile, in dem die Eingabe * der Fehler aufgetreten ist
* ungueltig ist.
* *
* Return: * Return:
* - ReadResult: * - ReadResult:
...@@ -215,24 +198,21 @@ void field_drop(Field *f) { ...@@ -215,24 +198,21 @@ void field_drop(Field *f) {
* ReadErr..., falls die Eingabe ungueltig ist. `f` ist dann nicht vollstaendig * ReadErr..., falls die Eingabe ungueltig ist. `f` ist dann nicht vollstaendig
* initialisiert * initialisiert
*/ */
ReadResult field_init_tile_list(Field *f) { ReadResult parse_input(List *this) {
while (1) { while (1) {
Tile *t = list_push(&f->tile_list); // neues Element in die Liste einfuegen Tile *p_tile = tile_new(); // neues Element erstellen
if (t == NULL) { if (p_tile == NULL) {
return ReadErrOutOfMemory; return ReadErrOutOfMemory;
} }
ReadResult result = read_line(t); ReadResult result = read_line(p_tile);
switch (result) { switch (result) {
case ReadOk: case ReadOk:
// Reichweite des Feldes ermitteln // einfuegen in die Liste
f->t_min.x = min(f->t_min.x, t->x); list_push(this, p_tile);
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);
break; break;
case ReadEof: case ReadEof:
list_pop(&f->tile_list); free(p_tile);
if (f->tile_list.size == 1) { if (this->num_tiles == 0) {
return ReadEof; return ReadEof;
} else { } else {
return ReadOk; return ReadOk;
...@@ -243,6 +223,24 @@ ReadResult field_init_tile_list(Field *f) { ...@@ -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 { typedef enum MallocResult {
MallocFailed, MallocFailed,
MallocOk, MallocOk,
...@@ -251,18 +249,17 @@ typedef enum MallocResult { ...@@ -251,18 +249,17 @@ typedef enum MallocResult {
* *
* Laufzeit: O(n) * Laufzeit: O(n)
*/ */
MallocResult field_init_tile_array(Field *f) { MallocResult array_from_list(Array *this, List* p_list) {
f->tile_array = malloc(f->tile_list.size * sizeof(Tile*)); this->tiles = malloc(p_list->num_tiles * sizeof(Tile*));
if(f->tile_array == NULL) { if(this->tiles == NULL) {
return MallocFailed; return MallocFailed;
} }
Tile *cur = f->tile_list.p_top; this->num_tiles = p_list->num_tiles;
f->num_tiles = f->tile_list.size; Tile *cur = p_list->p_top;
for (uint32_t i = 0; i < this->num_tiles; i++) {
for (uint32_t i = 0; i < f->tile_list.size; i++) { this->tiles[i] = cur;
f->tile_array[i] = cur; cur = cur->p_next;
cur = cur->p_n; this->tiles[i]->p_next = NULL;
f->tile_array[i]->p_n = NULL;
} }
return MallocOk; return MallocOk;
} }
...@@ -273,12 +270,12 @@ MallocResult field_init_tile_array(Field *f) { ...@@ -273,12 +270,12 @@ MallocResult field_init_tile_array(Field *f) {
* Rueckgabe: 0 falls alles ok * Rueckgabe: 0 falls alles ok
* 1 falls Dopplungen vorkommen TODO: enum * 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 i = 0; // vergleich mit oberer Zeile
uint32_t begin_line = 0; uint32_t begin_line = 0;
for (uint32_t j = 1; j < f->num_tiles; j++) { for (uint32_t j = 1; j < this->num_tiles; j++) {
Tile *p_cur = f->tile_array[j]; Tile *p_cur = this->tiles[j];
Tile *p_east = f->tile_array[j-1]; Tile *p_east = this->tiles[j-1];
// ermitteln der ost/west-Beziehung // ermitteln der ost/west-Beziehung
if (p_cur->y == p_east->y) { if (p_cur->y == p_east->y) {
if (p_cur->x == p_east->x) { if (p_cur->x == p_east->x) {
...@@ -292,14 +289,14 @@ int field_find_neighbours(Field *f) { ...@@ -292,14 +289,14 @@ int field_find_neighbours(Field *f) {
begin_line = i; begin_line = i;
} }
// ermitteln der nord/sued-Beziehung // 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) { if (p_north->y < p_cur->y - 1) {
i = begin_line; // Luecke zwischen zeilen i = begin_line; // Luecke zwischen zeilen
} else if (p_north->y == p_cur->y - 1) { } else if (p_north->y == p_cur->y - 1) {
// finden, ob paar existiert, zurzeit O(n). // finden, ob paar existiert, zurzeit O(n).
// TODO: lohnt sich binaere suche mit O(log n)? // TODO: lohnt sich binaere suche mit O(log n)?
for(;f->tile_array[i]->y < p_cur->y && i < begin_line; i++); for(;this->tiles[i]->y < p_cur->y && i < begin_line; i++);
p_north = f->tile_array[i]; p_north = this->tiles[i];
if (p_north->x == p_cur->x) { if (p_north->x == p_cur->x) {
p_north->p_s = p_cur; p_north->p_s = p_cur;
p_cur->p_n = p_north; p_cur->p_n = p_north;
...@@ -309,19 +306,19 @@ int field_find_neighbours(Field *f) { ...@@ -309,19 +306,19 @@ int field_find_neighbours(Field *f) {
return 0; return 0;
} }
void field_print(Field *f) { void array_print(Array *this) {
printf("# Array\n"); printf("# Array\n");
for (uint32_t i = 0; i < f->tile_list.size; i++) { for (uint32_t i = 0; i < this->num_tiles; i++) {
printf("%d %d\n", f->tile_array[i]->x, f->tile_array[i]->y); printf("%u %u\n", this->tiles[i]->x, this->tiles[i]->y);
} }
} }
int main (void) int main (void)
{ {
// erstellen des main Objekt // erstellen des Liste zum parsen des inputs
Field field; List tile_list;
field_init(&field); // initialiseren der Variablen list_init(&tile_list); // Liste ist owner von Tiles
ReadResult result = field_init_tile_list(&field); // lesen des Inputs ReadResult result = parse_input(&tile_list); // lesen des Inputs
switch (result) { switch (result) {
case ReadOk: case ReadOk:
break; break;
...@@ -329,44 +326,54 @@ int main (void) ...@@ -329,44 +326,54 @@ int main (void)
// bei leerer Eingabe nichts ausgeben // bei leerer Eingabe nichts ausgeben
return EXIT_SUCCESS; return EXIT_SUCCESS;
case ReadErrIntegerOverflow: case ReadErrIntegerOverflow:
fprintf(stderr, "Error in line %d: too big integer\n", field.tile_list.size); fprintf(stderr, "Error in line %d: too big integer\n", tile_list.num_tiles);
field_drop(&field); list_free(&tile_list);
return EXIT_FAILURE; return EXIT_FAILURE;
case ReadErrNonDigitCharacter: case ReadErrNonDigitCharacter:
fprintf(stderr, "Error in line %d: invalid character\n", field.tile_list.size); fprintf(stderr, "Error in line %d: invalid character\n", tile_list.num_tiles);
field_drop(&field); list_free(&tile_list);
return EXIT_FAILURE; return EXIT_FAILURE;
case ReadErrTooFewNumbers: case ReadErrTooFewNumbers:
fprintf(stderr, "Error in line %d: Too few numbers, expected exactly 2\n", fprintf(stderr, "Error in line %d: Too few numbers, expected exactly 2\n",
field.tile_list.size); tile_list.num_tiles);
field_drop(&field); list_free(&tile_list);
return EXIT_FAILURE; return EXIT_FAILURE;
case ReadErrTooManyNumbers: case ReadErrTooManyNumbers:
fprintf(stderr, "Error in line %d: Too much numbers, expected exactly 2\n", fprintf(stderr, "Error in line %d: Too much numbers, expected exactly 2\n",
field.tile_list.size); tile_list.num_tiles);
field_drop(&field); list_free(&tile_list);
return EXIT_FAILURE; return EXIT_FAILURE;
case ReadErrOutOfMemory: case ReadErrOutOfMemory:
fprintf(stderr, "Error in line %d: Failed to allocate more memory", 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; return EXIT_FAILURE;
} }
// turn the list into an array Array tile_array;
if(field_init_tile_array(&field) == MallocFailed) { // 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"); 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"); fprintf(stderr, "Error: Duplicated entry\n");
array_drop(&tile_array);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
//field_print(&field);
// TODO: Untertilesets finden // TODO: Untertilesets finden
// TODO: Problem fuer die Untertilesets loesen // TODO: Pro Untertileset schauen ob notwendiges kriterium
// TODO: Loesung ausgeben // TODO: Loesung ausgeben (schwerer Teil)
field_drop(&field); array_drop(&tile_array);
return EXIT_SUCCESS; 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