/*
  From tdk@dcn.davis.ca.us Wed Oct 25 14:33:55 1995
  Date: Wed, 25 Oct 1995 14:33:42 -0700
  Subject: SkipList Code
  From: Ted Krovetz <tdkrovetz@ucdavis.edu>
  To: "Phil Rogaway" <rogaway@cs.ucdavis.edu>
  
  Here's my simple C++ implementation of SkipLists. My version that uses 
  templates isn't working correctly, so this one will have to do.
  
  Besides the algorithm, the only interesting thing in the program is the 
  overloading of new and delete. I do this to create a variably sized struct.
  
  -Ted
  
 PS -- Almost no comments in the code. Sorry.

 */


//*****************************************************
//
// skiplist.h -- by Ted Krovetz (9/25/94)
//
//*****************************************************

typedef int datatype;

//*****************************************************

const int maxlevel = 16;
const int pratio = 4;

//*****************************************************

class listnode; // Forward declaration

//*****************************************************

class skiplist {
private:
    listnode *head;
public:
    skiplist();
    ~skiplist();
    int search(datatype data);
    void insert(datatype data);
    void remove(datatype data);
};

//*****************************************************






//*****************************************************
//
// skiplist.cp -- by Ted Krovetz (9/25/94)
//
//*****************************************************

#include <stdlib.h>
#include <time.h>
#include "sl.h"

//*****************************************************

typedef class listnode *listnodeptr;

//*****************************************************

class listnode {
private:
    datatype data;
    listnodeptr nextnode[1];
public:
    void* operator new(size_t size, int numptrs) { return malloc(size + 
(numptrs-1) * sizeof(listnodeptr)); }
    void operator  delete(void* ptr) { free(ptr); }
    datatype       getdata() { return data; }
    void           setdata(datatype newdata) { data = newdata; }
    listnodeptr    getnextnode(int i) { return nextnode[i]; }
    void           setnextnode(int i, listnodeptr n) { nextnode[i] = n; }
};

//*****************************************************

int randomlevel()
{
    int lvl = 1;    

    while (rand() < (RAND_MAX / pratio))
        lvl++;
    return (lvl <= maxlevel ? lvl : maxlevel);
}

//*****************************************************

skiplist::skiplist()
{
    head = new(maxlevel) listnode;
    for (int i=0;i<maxlevel;i++)
        head->setnextnode(i, NULL);
    srand((unsigned int)time(NULL));
}

//*****************************************************

skiplist::~skiplist()
{
    listnodeptr nodeptr, next;
    
    nodeptr = head->getnextnode(0);
    while (nodeptr != NULL) {
        next = nodeptr->getnextnode(0);
        delete nodeptr;
        nodeptr = next;
    }
    delete head;
}

//*****************************************************

int skiplist::search(datatype data)
{
    listnodeptr next, nodeptr = head;

    for (int i=maxlevel-1;i>=0;i--) {
        next = nodeptr->getnextnode(i);
        while ((next != NULL) && (next->getdata() < data)) {
            nodeptr = next;
            next = nodeptr->getnextnode(i);
        }
    }
    return ((next != NULL) && (next->getdata() == data));
}

//*****************************************************

void skiplist::insert(datatype data)
{
    listnodeptr next, update[maxlevel], nodeptr = head;
    int rlvl;
    int i;

    for (i=maxlevel-1;i>=0;i--) {
        next = nodeptr->getnextnode(i);
        while ((next != NULL) && (next->getdata() < data)) {
            nodeptr = next;
            next = nodeptr->getnextnode(i);
        }
        update[i] = nodeptr;
    }

    if ((next == NULL) || (next->getdata() != data)) {
        rlvl = randomlevel();
        nodeptr = new(rlvl) listnode;
        nodeptr->setdata(data);
        for (i=0;i<rlvl;i++) {
            nodeptr->setnextnode(i, update[i]->getnextnode(i));
            update[i]->setnextnode(i, nodeptr);
        }
    }
}

//*****************************************************

void skiplist::remove(datatype data)
{
    listnodeptr next, update[maxlevel], nodeptr = head;
    int i;

    for (i=maxlevel-1;i>=0;i--) {
        next = nodeptr->getnextnode(i);
        while ((next != NULL) && (next->getdata() < data)) {
            nodeptr = next;
            next = nodeptr->getnextnode(i);
        }
        update[i] = nodeptr;
    }
    
    if ((next != NULL) && (next->getdata() == data)) {
        i = 0;
        while ((i<maxlevel) && (update[i]->getnextnode(i) == next)) {
            update[i]->setnextnode(i, next->getnextnode(i));
            i++;
        }
        delete next;
    }
}

//*****************************************************


