/* disjset.c : Implements "path compression with union-by-size" 
 *             disjoint set ADT */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "disjset.h"

struct Disjoint_Set_Struct {
  SetType *array;
  unsigned int MaxNumSets;
};

Disjoint_Set DS_Create(unsigned int MaxNumSets) {
  Disjoint_Set ds;
  int i;

  ds = (Disjoint_Set) malloc(sizeof(struct Disjoint_Set_Struct));
  assert(ds != NULL);

  ds->array = (SetType*) malloc((MaxNumSets+1)*(sizeof(SetType)));
  assert(ds->array != NULL);

  /* all single value sets of size 1 */
  for(i=1; i<=MaxNumSets; i++)
    ds->array[i] = -1;
  
  ds->MaxNumSets = MaxNumSets;

  return(ds);
}

void DS_Destroy(Disjoint_Set ds) {
  if (ds != NULL) {
    free(ds->array);
    free(ds);
  }
}

SetType DS_Find(const Disjoint_Set ds, ElementType X) {
  assert(ds != NULL);
  assert((X > 0) && (X <= ds->MaxNumSets));
  if (ds->array[X] <= 0)
    return X;
  else
    return(ds->array[X] = DS_Find(ds, ds->array[X]));
}


void DS_SetUnion(Disjoint_Set ds, SetType Root1, SetType Root2) {
  assert(ds != NULL);
  assert(Root1 != Root2);
  assert((Root1 > 0) && (Root1 <= ds->MaxNumSets));
  assert((Root2 > 0) && (Root2 <= ds->MaxNumSets));

  if (ds->array[Root2] < ds->array[Root1]) {
    /* Make Root2 new root (Root1 is smaller that Root2) */
    /* (remember that the size is negative !*/

    ds->array[Root2] += ds->array[Root1];  /* increase the size */
    ds->array[Root1] = Root2;   /* make Root2 new root*/
  } else {
    /* Make Root1 one the new root */

    ds->array[Root1] += ds->array[Root2]; /* increase the size */
    ds->array[Root2] = Root1;   /* make Root1 new root*/
  }
}

void DS_Print(const Disjoint_Set ds) {
  int i;

  assert(ds != NULL);
  
  printf(" ");
  for(i=1; i<=ds->MaxNumSets; i++)
    printf("%5d ", i);
  printf("\n");
  for(i=1; i<=ds->MaxNumSets; i++)
    printf("------");
  printf("-\n|");
  for(i=1; i<=ds->MaxNumSets; i++)
    printf("%5d|", ds->array[i]);
  printf("\n-");
  for(i=1; i<=ds->MaxNumSets; i++)
    printf("------");
  printf("\n");
  
}
