Algorithm Alley
by Thomas Gettys

Listing One
//***********************************************************************
// This is the actual Graham scan algorithm. It is called after the pivot 
// point has been located and the rest of the points have been sorted by 
// their polar angle.

void Graham_Scan(point S[], int N)
{
   int i;
   point p;

   Push(S[0]);
   Push(S[1]);
   Push(S[2]);

   for (i = 3; i < N; i++)
   {
      while (CrossProduct(Stack2nd, StackTop, S[i]) < 0)
      {
         Pop(&p);
      };
      Push(S[i]);
   }
}


Listing Two
typedef struct
{
   int x, y;
} point;

// Find point with smallest y coordinate; if there is more
// than one select the one with the smallest x coordinate.

int LocatePivot(point S[], int N)
{
   int i, ndx, minx, miny;

// initialize minimum coordinates found so far
   ndx  = 0;
   minx = S[ndx].x;
   miny = S[ndx].y;

// locate lowest point in set
   for (i = 1; i < N; i++)
   {
      if (S[i].y > miny) continue;

//    found a candidate for a new pivot
      if (S[i].y < miny)
      {
         ndx = i;
         miny = S[i].y;
      }
      else if (S[i].x < minx)
      {
         ndx = i;
         minx = S[i].x;
      }
   }

// all done - return index of pivot point
   return(ndx);
}

Listing Three
#define sizeof_Stack 100
#define StackTop     stack[TOS_ptr-1]
#define Stack2nd     stack[TOS_ptr-2]

int TOS_ptr = 0;           // Top Of Stack pointer
point stack[sizeof_Stack]; // the actual point stack array

//*********************************************************
// pushes point p onto the stack
// if successful Push() returns 1
// on stack overflow Push() returns 0

int Push(point p)
{
   if (TOS_ptr == sizeof_Stack) return(0);

   stack[TOS_ptr++] = p;
   return(1);
}
//*********************************************************
// pops a point off of the stack
// if successful Pop() returns 1
// on stack underflow Pop() returns 0

int Pop(point *p)
{
   if (TOS_ptr == 0) return(0);
   *p = stack[--TOS_ptr];
   return(1);
}

Listing Four
//*************************************************************************
// Computes the cross product (p1-p0)x(p2-p0). If p2 is to the left of the 
// line from p0 to p1 the result will be positive.

int CrossProduct(point p0, point p1, point p2)
{
   int xprod;
   xprod = (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
   return(xprod);
}
//*********************************************************
// Support function for qsort()
// a < b if a makes a smaller angle with Pivot than does b

int compare_points(const void *a, const void *b)
{
   int xprod;
   point *point_a, *point_b;

   point_a = (point *)a;
   point_b = (point *)b;

   xprod = CrossProduct(Pivot, *point_a, *point_b);

   if (xprod < 0) return(+1);    // a > b
   else
   if (xprod > 0) return(-1);    // a < b

   return(0);                    // a = b
}

Listing Five
point Pivot, S[100];

void main(void)
{
   int i, N;
   point p;

// make up some points
   N = 12;
   randomize();
   for (i = 0; i < N; i++)
   {
      S[i].x = random(10);
      S[i].y = random(10);
      printf("(%3d, %3d)\n", S[i].x, S[i].y);
   }
// find the convex hull
   i = LocatePivot(S, N);
   Pivot = S[i];
   S[i]  = S[0];
   S[0]  = Pivot;

   qsort((void *)&S[1], N-1, sizeof(S[0]), compare_points);

   Graham_Scan(S, N);

// output points of convex hull in clockwise order
   for (i = 0; Pop(&p) != 0; i++)
   {
      printf("(%3d, %3d)\n", p.x, p.y);
   }
   printf("%d points in convex hull\n", i);
}




3


