[email protected]
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "../tools/contest.h"
#define CHARS 256
#define INSERTBREAK 20
typedef unsigned char* string;
#define MAXBLOCKS 100
#define TRUE 1
#define FALSE 0
#define MAX(a, b) ((a) > (b) ? (a) : (b))
typedef int boolean;
typedef int character;
typedef struct {
	void *block[MAXBLOCKS];
	int allocnr;
	int nr;
	int blocksize;
	void *current, *first, *last;
} memory;
static inline void initmem(memory *m, int elemsize, int blocksize)
{
   m->blocksize = MAX(blocksize, 1000) * elemsize;
   m->block[0] = malloc(m->blocksize);
   m->allocnr = 0;
   m->nr = -1;
   m->current = m->first = m->last = NULL;
}
static inline void *allocmem(memory *m, int elemsize)
{
   if (m->current < m->last)
      m->current = (void *) ((char *) (m->current) + elemsize);
   else {
      if (++m->nr >= MAXBLOCKS) return NULL;
      if (m->nr > m->allocnr) {
         m->block[m->nr] = malloc(m->blocksize);
         m->allocnr++;
      }
      m->current = m->first = m->block[m->nr];
      m->last = (void *)
         ((char *) (m->first) + m->blocksize - elemsize);
   }
   return m->current;
}
static inline void *deallocmem(memory *m, int elemsize)
{
   if (m->current > m->first)
      m->current = (void *) ((char *) (m->current) - elemsize);
   else {
      m->nr--;
      if (m->nr >= 0) {
         m->first = m->block[m->nr];
         m->current = m->last = (void *)
            ((char *) (m->first) + m->blocksize - elemsize);
      } else
         m->current = m->first = m->last = NULL;
   }
   return m->current;
}
static inline void resetmem(memory *m)
{
   m->nr = -1;
   m->current = m->first = m->last = NULL;
}
static inline void freemem(memory *m)
{
   int i;
   for (i = 0; i <= m->allocnr; i++)
      free(m->block[i]);
   m->nr = m->allocnr = -1;
   m->current = m->first = m->last = NULL;
}
typedef struct listrec *list;
struct listrec {
   string str;
   list next;
   int length;
};
static inline int scmp(unsigned char *s1, unsigned char *s2)
{
    while( *s1 != '\0' && *s1 == *s2 )
        s1++, s2++;
    return( *s1-*s2 );
}
static inline list Insertsort(list r, list *tail, int p)
{
   list fi, la, t;
   for (fi = la = r, r = r->next; r; r = la->next)
      if (scmp(r->str+p, la->str+p) >= 0) 
         la = r;
      else if (scmp(r->str+p, fi->str+p) <= 0) { 
         la->next = r->next;
         r->next = fi;
         fi = r;
      } else { 
          for (t = fi; scmp(r->str+p, t->next->str+p) >= 0; )
            t = t->next;
         la->next = r->next;
         r->next = t->next;
         t->next = r;
      }
   *tail = la;
   return fi;
}
#define IS_ENDMARK(ch) (ch == '\0')
#define CHAR(s, p) s[p]
typedef struct grouprec *group;
typedef struct bucketrec *bucket;
struct grouprec {
   list head, tail; 
   group next;      
   group nextunf;   
   group insp;      
   boolean finis;   
};
struct bucketrec {
   list head, tail; 
   int size;        
   group tag;       
   bucket next;     
};
static memory groupmem[1];
static memory bucketmem[1];
static void intobucket(bucket *b, list head, list tail,
                       int size, group g)
{
   bucket btemp = *b, newb;
   if (!btemp || btemp->tag != g) {   
      newb = (bucket) allocmem(bucketmem, sizeof(struct bucketrec));
      newb->next = btemp;
      newb->head = head;
      newb->size = size;
      newb->tag = g;
      *b = btemp = newb;
   } else {   
      btemp->tail->next = head;
      btemp->size += size;
   }
   tail->next = NULL;
   btemp->tail = tail;
}
static void intobuckets(group g, bucket b[], int pos)
{
   group prevg;
   character ch, prevch;
   boolean split;
   list tail, tailn;
   int size;
   resetmem(bucketmem);
   for (prevg = g, g = g->nextunf ; g; g = g->nextunf) {
      if (g->finis)
         {prevg->nextunf = g->nextunf; continue;}
      tail = g->head; split = FALSE;
      prevch = CHAR(tail->str, pos); size = 1;
      for ( ; (tailn = tail->next); tail = tailn) {
         ch = CHAR(tailn->str, pos); size++;
         if (ch == prevch) continue;
         intobucket(b+prevch, g->head, tail, size-1, g);
         g->head = tailn; split = TRUE;
         prevch = ch; size = 1;
      }
      if (split) {
         intobucket(b+prevch, g->head, tail, size, g);
         g->head = NULL;
         prevg = g;
      } else if (IS_ENDMARK(prevch))
         prevg->nextunf = g->nextunf;
      else
         prevg = g;
   }
}
static void intogroup(group g, list head, list tail, boolean finis)
{
   group newg;
   if (!g->head) {   
      g->head = head;
      g->tail = tail;
      g->finis = finis;
      g->insp = g;
   } else if (finis && g->insp->finis) {  
      g->insp->tail->next = head;         
      g->insp->tail = tail;
   }
   else {   
      newg = (group) allocmem(groupmem, sizeof(struct grouprec));
      newg->head = head;
      newg->tail = tail;
      newg->next = g->insp->next;
      newg->nextunf = g->insp->nextunf;
      newg->finis = finis;
      g->insp = g->insp->nextunf = g->insp->next = newg;
   }
}
static void intogroups(bucket b[], int pos)
{
   character ch;
   bucket s;
   boolean finis;
   for (ch = 0; ch < CHARS; ch++) {
      if (!b[ch]) continue;
      for (s = b[ch]; s; s = s->next) {
         finis = IS_ENDMARK(ch);
         if (s->size < INSERTBREAK && !finis) {
            if (s->size > 1)
               s->head = Insertsort(s->head, &s->tail, pos);
            finis = TRUE;
         }
         intogroup(s->tag, s->head, s->tail, finis);
      }
      b[ch] = NULL;
   }
}
static list collect(group g)
{
   list head, tail;
   g = g->next;
   head = g->head;
   tail = g->tail;
   for (g = g->next; g; g = g->next) {
      tail->next = g->head;
      tail = g->tail;
   }
   return head;
}
static inline list forward1(list t, int n)
{
   static bucket b[CHARS];   
   group g, g2;              
   int pos = 0;              
   if (n<2) return t;
   initmem(groupmem, sizeof(struct grouprec), n/15);
   initmem(bucketmem, sizeof(struct bucketrec), n/5);
   
   g = (group) allocmem(groupmem, sizeof(struct grouprec));
   g2 = (group) allocmem(groupmem, sizeof(struct grouprec));
   g->next = g->nextunf = g2;
   g2->head = t;
   g2->next = g2->nextunf = NULL; 
   g2->finis = FALSE;
   intobuckets(g, b, pos);
   while (g->nextunf) {
      pos++;
      intogroups(b, pos);
      intobuckets(g, b, pos);
   }
   t = collect(g);
   freemem(bucketmem);
   freemem(groupmem);
   return t;
}
void frssort1(string strings[], size_t scnt)
{
    list listnodes;
    size_t i;
    
    listnodes = (list ) calloc(scnt, sizeof(struct listrec));
    
    for( i=0; i<scnt; i++)
    {
        listnodes[i].str = strings[i];
        if (i<(scnt-1))
            listnodes[i].next = &listnodes[i+1];
        else
            listnodes[i].next = NULL;
    }
    
    list sortednodes = forward1(listnodes, scnt);
    
    for (i = 0;  i < scnt ; i++, sortednodes=sortednodes->next)
        strings[i] = sortednodes->str;
    free(listnodes);
}
void nilsson_forward8(unsigned char **strings, size_t n)
{
    return frssort1(strings, n);
}
CONTESTANT_REGISTER(nilsson_forward8,
                    "nilsson/forward8",
                    "Forward Radix Sort 8-bit by Stefan Nilsson")