#include <stdio.h>
#include <sys/types.h>
#include <sys/times.h>
#include <math.h>
#define maxN 5000
#define maxB 50000

typedef char* itemType;

#define less(A, B) (strcmp(A, B) < 0)
#define exch(A, B) { itemType t = A; A = B; B = t; } 
#define compexch(A, B) if (less(A, B)) exch(A, B);
#define IENN 10

static char* buf;
static int cnt = 0;
int debug = 0;

int scanItem(char** x)
  { int t;
    *x = &buf[cnt]; 
    t = scanf("%s", *x); cnt += strlen(*x)+1;
    return t;
  }  
void showItem(char* x) 
  { printf("%s ", x); }  
void showArray(itemType a[], int l, int r)
  { int i;
    for (i = l; i <= r; i++)
      if ((r-l < IENN) || (i-l+1 < IENN/2) || (r-i+1 < IENN/2)) 
        showItem(a[i]); 
      else if (i == l+IENN/2-1) printf ("... ");  
    printf("\n");  
  }  

void scanArray(itemType a[], int N)
  { int i;
    for (i = 0; i < N; i++) scanItem(&a[i]); 
  }

void copyArray(itemType a[], itemType b[], int N)
  { int i;
    for (i = 0; i < N; i++) { a[i] = b[i]; } 
  }

void selection(itemType a[], int l, int r)
  { int i, j;
    for (i = l; i < r; i++)
      { int min = i;
        for (j = i+1; j <= r; j++) 
            if (less(a[j], a[min])) min = j;
        exch(a[i], a[min]);
      } 
  }

void insertionExch(itemType a[], int l, int r)
  { int i, j; 
    for (i = l+1; i <= r; i++)
      for (j = i; j > l; j--)
        if (less(a[j-1], a[j])) break;
        else exch(a[j-1], a[j]);
  }

void insertion(itemType a[], int l, int r)
  { int i;
    for (i = l+1; i <= r; i++) 
      if (less(a[i], a[l])) exch(a[i], a[l]);
    for (i = l+2; i <= r; i++)
      { int j = i; itemType v = a[i]; 
        while (less(v, a[j-1]))
          { a[j] = a[j-1]; j--; }
        a[j] = v; 
      } 
  }

void bubble(itemType a[], int l, int r)
  { int i, j;
    for (i = l; i < r; i++)
      for (j = r; j > i; j--) 
        if (less(a[j], a[j-1])) exch(a[j], a[j-1]);
  }

void shaker(itemType a[], int l, int r)
  { int i, j, ll = l, rr = r, tl = l, tr = r;
    while (ll < rr)
      {
        tl = rr; tr = ll;
        for (j = rr; j > ll; j--) 
          if (less(a[j], a[j-1])) 
            { tl = j; exch(a[j], a[j-1]); }
        for (j = ll; j < rr; j++) 
          if (less(a[j+1], a[j])) 
            { tr = j; exch(a[j+1], a[j]); }
        ll = tl; rr = tr;
      }
  }

// Driver code
struct tms buffer; 

long doit(void (*sortprog)(), itemType a[], int l, int r)
  {
    int i; long t;
    times(&buffer);
    t = buffer.tms_utime + buffer.tms_stime;
    (*sortprog)(a, l, r);
    times(&buffer);
    for (i = l; i < r; i++)
      if (less(a[i+1], a[i])) return -1;
    if (debug) showArray(a, l, r);
    return buffer.tms_utime + buffer.tms_stime - t;
  }

main(int argc, char *argv[])
  { itemType *a, *b;
    int N; 
    int c1, c2, c3, c4, c5;

    if (argc == 2) debug = atoi(argv[1]);

    buf = malloc(maxB*sizeof(char));
    a = malloc(maxN*sizeof(itemType));
    b = malloc(maxN*sizeof(itemType));


    printf("    N       S      I*     I      B     B*    \n");
    for (N = 250; N <= 4000; N *= 2)
      {
        scanArray(b, N);
        copyArray(a, b, N); c1 = doit(selection, a, 0, N-1);
        copyArray(a, b, N); c2 = doit(insertionExch, a, 0, N-1);
        copyArray(a, b, N); c3 = doit(insertion, a, 0, N-1);
        copyArray(a, b, N); c4 = doit(bubble, a, 0, N-1);
        copyArray(a, b, N); c5 = doit(shaker, a, 0, N-1);
        printf("%6d %6d %6d %6d %6d %6d\n", N, c1, c2, c3, c4, c5);
      }

    printf("\n");
    printf("           S:  Selection sort\n");
    printf("           I*: Insertion sort (exchange-based)\n");
    printf("           I:  Insertion sort\n");
    printf("           B:  Bubble sort\n");
    printf("           B*: Shaker sort\n");
  }

