Skip to content

Instantly share code, notes, and snippets.

@rah003
Created December 2, 2018 11:52
Show Gist options
  • Save rah003/19cda206520b29015ff240a4411b75c6 to your computer and use it in GitHub Desktop.
Save rah003/19cda206520b29015ff240a4411b75c6 to your computer and use it in GitHub Desktop.
/**
* 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