Created
December 2, 2018 11:52
-
-
Save rah003/19cda206520b29015ff240a4411b75c6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Kostra programu pro 3. projekt IZP 2018/19 | |
* | |
* Jednoducha shlukova analyza: 2D nejblizsi soused. | |
* Single linkage | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <assert.h> | |
#include <math.h> // sqrtf | |
#include <limits.h> // INT_MAX | |
#include <string.h> // INT_MAX | |
/***************************************************************** | |
* Ladici makra. Vypnout jejich efekt lze definici makra | |
* NDEBUG, napr.: | |
* a) pri prekladu argumentem prekladaci -DNDEBUG | |
* b) v souboru (na radek pred #include <assert.h> | |
* #define NDEBUG | |
*/ | |
#ifdef NDEBUG | |
#define debug(s) | |
#define dfmt(s, ...) | |
#define dint(i) | |
#define dfloat(f) | |
#else | |
// vypise ladici retezec | |
#define debug(s) printf("- %s\n", s) | |
// vypise formatovany ladici vystup - pouziti podobne jako printf | |
#define dfmt(s, ...) printf(" - "__FILE__":%u: "s"\n",__LINE__,__VA_ARGS__) | |
// vypise ladici informaci o promenne - pouziti dint(identifikator_promenne) | |
#define dint(i) printf(" - " __FILE__ ":%u: " #i " = %d\n", __LINE__, i) | |
// vypise ladici informaci o promenne typu float - pouziti | |
// dfloat(identifikator_promenne) | |
#define dfloat(f) printf(" - " __FILE__ ":%u: " #f " = %g\n", __LINE__, f) | |
#endif | |
/***************************************************************** | |
* Deklarace potrebnych datovych typu: | |
* | |
* TYTO DEKLARACE NEMENTE | |
* | |
* struct obj_t - struktura objektu: identifikator a souradnice | |
* struct cluster_t - shluk objektu: | |
* pocet objektu ve shluku, | |
* kapacita shluku (pocet objektu, pro ktere je rezervovano | |
* misto v poli), | |
* ukazatel na pole shluku. | |
*/ | |
struct obj_t { | |
int id; | |
float x; | |
float y; | |
}; | |
struct cluster_t { | |
int size; | |
int capacity; | |
struct obj_t *obj; | |
}; | |
/***************************************************************** | |
* Deklarace potrebnych funkci. | |
* | |
* PROTOTYPY FUNKCI NEMENTE | |
* | |
* IMPLEMENTUJTE POUZE FUNKCE NA MISTECH OZNACENYCH 'TODO' | |
* | |
*/ | |
/* | |
Inicializace shluku 'c'. Alokuje pamet pro cap objektu (kapacitu). | |
Ukazatel NULL u pole objektu znamena kapacitu 0. | |
*/ | |
void init_cluster(struct cluster_t *c, int cap) | |
{ | |
assert(c != NULL); | |
assert(cap >= 0); | |
//TODO | |
c->size = 0; | |
c->capacity = cap; | |
c->obj = malloc(cap * sizeof(struct obj_t)); | |
if(c->obj == NULL) { | |
c->capacity = 0; | |
} | |
} | |
/* | |
Odstraneni vsech objektu shluku a inicializace na prazdny shluk. | |
*/ | |
void clear_cluster(struct cluster_t *c) | |
{ | |
// TODO | |
free(c->obj); //free | |
init_cluster(c, 0); //prazdny | |
} | |
/// Chunk of cluster objects. Value recommended for reallocation. | |
const int CLUSTER_CHUNK = 10; | |
/* | |
Zmena kapacity shluku 'c' na kapacitu 'new_cap'. | |
*/ | |
struct cluster_t *resize_cluster(struct cluster_t *c, int new_cap) | |
{ | |
// TUTO FUNKCI NEMENTE | |
assert(c); | |
assert(c->capacity >= 0); | |
assert(new_cap >= 0); | |
if (c->capacity >= new_cap) | |
return c; | |
size_t size = sizeof(struct obj_t) * new_cap; | |
void *arr = realloc(c->obj, size); | |
if (arr == NULL) | |
return NULL; | |
c->obj = (struct obj_t*)arr; | |
c->capacity = new_cap; | |
return c; | |
} | |
/* | |
Prida objekt 'obj' na konec shluku 'c'. Rozsiri shluk, pokud se do nej objekt | |
nevejde. | |
*/ | |
void append_cluster(struct cluster_t *c, struct obj_t obj) | |
{ | |
// TODO | |
if(c->size >= c->capacity) { | |
int nova_vel = c->capacity + CLUSTER_CHUNK; | |
resize_cluster(c, nova_vel); | |
} | |
c->obj[c->size] = obj; | |
c->size++; | |
} | |
/* | |
Seradi objekty ve shluku 'c' vzestupne podle jejich identifikacniho cisla. | |
*/ | |
void sort_cluster(struct cluster_t *c); | |
/* | |
Do shluku 'c1' prida objekty 'c2'. Shluk 'c1' bude v pripade nutnosti rozsiren. | |
Objekty ve shluku 'c1' budou serazeny vzestupne podle identifikacniho cisla. | |
Shluk 'c2' bude nezmenen. | |
*/ | |
void merge_clusters(struct cluster_t *c1, struct cluster_t *c2) | |
{ | |
assert(c1 != NULL); | |
assert(c2 != NULL); | |
// TODO | |
for (int i = 0; i < c2->size; i++) { | |
append_cluster(c1, c2->obj[i]); | |
} | |
sort_cluster(c1); | |
} | |
/**********************************************************************/ | |
/* Prace s polem shluku */ | |
/* | |
Odstrani shluk z pole shluku 'carr'. Pole shluku obsahuje 'narr' polozek | |
(shluku). Shluk pro odstraneni se nachazi na indexu 'idx'. Funkce vraci novy | |
pocet shluku v poli. | |
*/ | |
int remove_cluster(struct cluster_t *carr, int narr, int idx) | |
{ | |
assert(idx < narr); | |
assert(narr > 0); | |
// TODO | |
int nova_vel = narr-1; | |
clear_cluster(&carr[idx]); | |
for (int i = idx; i < nova_vel; i++) { | |
carr[i] = carr[i+1]; | |
} | |
return nova_vel; | |
} | |
/* | |
Pocita Euklidovskou vzdalenost mezi dvema objekty. | |
*/ | |
float obj_distance(struct obj_t *o1, struct obj_t *o2) | |
{ | |
assert(o1 != NULL); | |
assert(o2 != NULL); | |
// TODO | |
return sqrtf((o1->x - o2->x)*(o1->x - o2->x) + (o1->x - o2->x)*(o1->x - o2->x)); | |
} | |
/* | |
Pocita vzdalenost dvou shluku. | |
*/ | |
float cluster_distance(struct cluster_t *c1, struct cluster_t *c2) | |
{ | |
assert(c1 != NULL); | |
assert(c1->size > 0); | |
assert(c2 != NULL); | |
assert(c2->size > 0); | |
// TODO | |
float lenght; | |
float min_lenght = obj_distance(&c1->obj[0], &c2->obj[0]); | |
for(int i=c1->size; i == 0; i--){ | |
for(int j=c2->size; j == 0; j--){ | |
lenght = obj_distance(&c1->obj[i], &c2->obj[j]); | |
if(lenght < min_lenght){ | |
min_lenght = lenght; | |
} | |
} | |
} | |
return min_lenght; | |
} | |
/* | |
Funkce najde dva nejblizsi shluky. V poli shluku 'carr' o velikosti 'narr' | |
hleda dva nejblizsi shluky. Nalezene shluky identifikuje jejich indexy v poli | |
'carr'. Funkce nalezene shluky (indexy do pole 'carr') uklada do pameti na | |
adresu 'c1' resp. 'c2'. | |
*/ | |
//Uplne chapu co mam delat... | |
void find_neighbours(struct cluster_t *carr, int narr, int *c1, int *c2) | |
{ | |
assert(narr > 0); | |
// TODO | |
*c1 = 0; | |
*c2 = 1; | |
float lenght; | |
float min_lenght = cluster_distance(&carr[0], &carr[1]); | |
for(int i=0; i == narr-1; i++){ | |
for(int j=i+1; j == narr-1; j++){ | |
lenght = cluster_distance(&carr[i], &carr[j]); | |
if(lenght < min_lenght){ | |
min_lenght = lenght; | |
*c1 = i; | |
*c1 = j; | |
} | |
} | |
} | |
} | |
// pomocna funkce pro razeni shluku | |
static int obj_sort_compar(const void *a, const void *b) | |
{ | |
// TUTO FUNKCI NEMENTE | |
const struct obj_t *o1 = (const struct obj_t *)a; | |
const struct obj_t *o2 = (const struct obj_t *)b; | |
if (o1->id < o2->id) return -1; | |
if (o1->id > o2->id) return 1; | |
return 0; | |
} | |
/* | |
Razeni objektu ve shluku vzestupne podle jejich identifikatoru. | |
*/ | |
void sort_cluster(struct cluster_t *c) | |
{ | |
// TUTO FUNKCI NEMENTE | |
qsort(c->obj, c->size, sizeof(struct obj_t), &obj_sort_compar); | |
} | |
/* | |
Tisk shluku 'c' na stdout. | |
*/ | |
void print_cluster(struct cluster_t *c) | |
{ | |
// TUTO FUNKCI NEMENTE | |
for (int i = 0; i < c->size; i++) | |
{ | |
if (i) putchar(' '); | |
printf("%d[%g,%g]", c->obj[i].id, c->obj[i].x, c->obj[i].y); | |
} | |
putchar('\n'); | |
} | |
/* | |
Ze souboru 'filename' nacte objekty. Pro kazdy objekt vytvori shluk a ulozi | |
jej do pole shluku. Alokuje prostor pro pole vsech shluku a ukazatel na prvni | |
polozku pole (ukalazatel na prvni shluk v alokovanem poli) ulozi do pameti, | |
kam se odkazuje parametr 'arr'. Funkce vraci pocet nactenych objektu (shluku). | |
V pripade nejake chyby uklada do pameti, kam se odkazuje 'arr', hodnotu NULL. | |
*/ | |
int load_clusters(char *filename, struct cluster_t **arr) | |
{ | |
assert(arr != NULL); | |
// TODO | |
char line[10]; | |
int pocet = 0; | |
FILE * fp; | |
struct obj_t object; | |
if((fp = fopen(filename, "r")) == NULL) { | |
printf("soubor se nepodarilo otevrit"); | |
return 1; | |
} | |
fgets(line, 10, fp); | |
for (int i = 0; i<(int)strlen(line); i++) { | |
if(line[i] >= '0' && line[i] <= '9') { | |
pocet = pocet * 10 + (line[i] - '0'); | |
} else { | |
continue; | |
} | |
} | |
*arr = malloc(pocet * sizeof(struct cluster_t)); | |
for (int i = 0; i < pocet; i++) { | |
fscanf(fp,"%d %f %f", &(object.id), &(object.x), &(object.y)); | |
init_cluster(&(*arr)[i], 1); | |
append_cluster(&(*arr)[i], object); | |
} | |
fclose(fp); | |
return pocet; | |
} | |
/* | |
Tisk pole shluku. Parametr 'carr' je ukazatel na prvni polozku (shluk). | |
Tiskne se prvnich 'narr' shluku. | |
*/ | |
void print_clusters(struct cluster_t *carr, int narr) | |
{ | |
printf("Clusters:\n"); | |
for (int i = 0; i < narr; i++) | |
{ | |
printf("cluster %d: ", i); | |
print_cluster(&carr[i]); | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
struct cluster_t *clusters; | |
// TODO | |
(void)argc; | |
if (argc <= 1) | |
{ | |
printf("chybi argument\n"); | |
return 0; | |
} | |
int cislo = (int) strtol(argv[2], NULL, 10); | |
int count = load_clusters(argv[1], &clusters); | |
int c1 = 0; | |
int c2 = 0; | |
while (cislo > count) { | |
find_neighbours(clusters, count, &c1, &c2); | |
merge_clusters(&clusters[c1], &clusters[c2]); | |
cislo = remove_cluster(clusters, cislo, c2); | |
} | |
if (cislo == -1) { | |
clear_cluster(clusters); | |
} | |
print_clusters(clusters, cislo); | |
for (int i = 0; i < count; i++) { | |
clear_cluster(&clusters[i]); | |
} | |
// uvolneni pameti pole shluku | |
free(clusters); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment