Insiemi disgiunti - Soluzione


/* Insiemi disgiunti */

#include <stdio.h>

typedef struct forest_frame* Forest;

typedef struct node {
	char name;
	int  rank;
	int  father;
} Node;

typedef struct forest_frame {
	int  size;
	Node*  nodearray;
} Forest_Frame;

typedef char* Set; /* trattiamo insiemi di caratteri */

typedef Forest DisjointSets;

/* Prototipi funzioni pubbliche */

DisjointSets Create(Set s);
/* pre: s e' ordinata alfabeticamente senza ripetizioni
   post: ritorna la partizione triviale dell'insieme
   di caratteri rappresentato da s */

void Union(DisjointSets d, char x, char y);
/* pre: x, y sono rappresentanti di due elementi distinti della partizione */
/* rimpiazza in d gli insiemi i cui rappresentanti sono x e y
   con la loro unione */

int Find(DisjointSets d, char x);
/* pre: x e' elemento dell'unione della partizione d
   post: ritorna l'indice del rappresentante dell'elemento di d cui
        x appartiene */

/* Implementazioni */

DisjointSets Create(Set s)
{
	int i; Forest f;
	
	f = (Forest) malloc (sizeof(Forest_Frame));
	f->size = strlen(s);
	f->nodearray = (Node*) malloc (f->size * sizeof(Node));
	for (i = 0; i < f->size; i++) {
		f->nodearray[i].name = s[i];
		f->nodearray[i].rank = 0;
		f->nodearray[i].father = i;
	};
	return f;
}

int DicSearch(char x, Node v[], int i, int j)
/* post: ritorna l'indice di x in v[i..j].name se esiste,
         -1 altrimenti */
{
	int m;

	if (i > j) return -1;
	else {
		m = (i+j) / 2;
		if (v[m].name == x) return m;
		else if (v[m].name < x) return DicSearch(x,v,m+1,j);
		else return DicSearch(x,v,i,m-1);
	}
}
	
void Link(DisjointSets d, int i, int j)
/* effettua l'unione per rango degli alberi con
   radice nei vertici di offset i e j in d->nodearray */
{
	if (d->nodearray[i].rank <= d->nodearray[j].rank) {
		d->nodearray[i].father = j;
		d->nodearray[j].rank++;
	} else d->nodearray[j].father = i;
}

void Union(DisjointSets d, char x, char y)
{
	Link(d, DicSearch(x,d->nodearray,0,d->size),
	        DicSearch(y,d->nodearray,0,d->size));
}

int find_compact(DisjointSets d, int i)
/*  pre:  i e' l'indice di un vertice in d->nodearray
    post: ritorna l'indice della radice cui appartiene
          il vertice di offset i in d->nodearray; effettua la
          compressione del find path */
{
	if (d->nodearray[i].father == i) return i;
	else {
	    d->nodearray[i].father = find_compact(d,d->nodearray[i].father);
	    return d->nodearray[i].father;
	}
}

int Find(DisjointSets d, char x)
{
	int i = DicSearch(x,d->nodearray,0,d->size);
	if (i != -1) return find_compact(d,i);
	else return -1;
}


/* Utilita' */

void WriteForest(Forest f)
{
	int i;
	
	for (i = 0; i < f->size; i++)
		printf("%d: (%c,%d,%d)\n", i,
		                     f->nodearray[i].name,
		                     f->nodearray[i].rank,
		                     f->nodearray[i].father);
	printf("\n");
}

/* eof */