Initial commit.

This commit is contained in:
Darko 2015-03-20 20:32:11 +01:00
commit 57e0a96f18
8 changed files with 588 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.o
*.so
sl

28
LICENSE Normal file
View file

@ -0,0 +1,28 @@
Copyright (c) 2015, Darko Poljak
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of mergesort nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

4
README.rst Normal file
View file

@ -0,0 +1,4 @@
skiplist
=========
Academic example of skip list implementation in C.

134
main.c Normal file
View file

@ -0,0 +1,134 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "skiplist.h"
#include "x.h"
#define MAXBUF 80
#define KEYCNT 1000
int dodebug = 1;
int main(int argc, char **argv)
{
slist sl;
int key;
sl_node *x;
int res;
int i;
int keys[KEYCNT];
int failed = 0;
int cntnew;
int cntsame;
/*
char foo[MAXBUF];
sl_init(&sl);
sl_print(&sl);
printf("addition\n");
while (fgets(foo, MAXBUF - 1, stdin) != NULL) {
if (foo[0] == '\n') {
break;
}
key = atoi(foo);
sl_add(&sl, key, NULL);
sl_print(&sl);
}
printf("search\n");
while (fgets(foo, MAXBUF - 1, stdin) != NULL) {
if (foo[0] == '\n') {
break;
}
key = atoi(foo);
x = sl_find(&sl, key);
if (x) {
printf("found: %d\n", x->key);
} else {
printf("not found\n");
}
}
printf("remove\n");
while (fgets(foo, MAXBUF - 1, stdin) != NULL) {
if (foo[0] == '\n') {
break;
}
key = atoi(foo);
res = sl_remove(&sl, key);
sl_print(&sl);
if (res) {
printf("removed\n");
} else {
printf("not found\n");
}
}
sl_free(&sl);
*/
sl_init(&sl);
dodebug = 0;
failed = 0;
cntnew = cntsame = 0;
for (i = 0; i < KEYCNT; ++i) {
key = random() % KEYCNT;
keys[i] = key;
res = sl_add(&sl, key, NULL);
switch(res) {
case SL_ADD_NEW:
++cntnew;
break;
case SL_ADD_SAME:
++cntsame;
break;
default:
failed = 1;
break;
}
}
printf("added %d new keys, %d same keys\n", cntnew, cntsame);
dodebug = 1;
sl_print(&sl);
dodebug = 0;
cntnew = cntsame = 0;
for (i = 0; i < KEYCNT; ++i) {
key = keys[i];
x = sl_find(&sl, key);
if (!x) {
failed = 1;
break;
}
}
if (failed) {
fatal("find failed, report bug\n");
}
cntnew = cntsame = 0;
for (i = 0; i < KEYCNT; ++i) {
key = keys[i];
res = sl_remove(&sl, key);
switch (res) {
case 0:
++cntsame;
break;
case 1:
++cntnew;
break;
default:
break;
}
if (sl_find(&sl, key)) {
failed = 1;
break;
}
}
if (failed) {
fatal("remove failed, report bug\n");
}
printf("removed %d new keys, %d same keys\n", cntnew, cntsame);
sl_free(&sl);
return 0;
}

292
skiplist.c Normal file
View file

@ -0,0 +1,292 @@
#include <strings.h>
#include "skiplist.h"
#include "x.h"
sl_node *_sl_create_node(int key, void *data)
{
sl_node *x = xmalloc(sizeof(sl_node));
x->key = key;
x->data = data;
x->next = x->prev = x->below = x->above = NULL;
return x;
}
void sl_init(slist *sl)
{
sl_node *x = _sl_create_node(KEY_INF_MIN, NULL);
sl_node *y = _sl_create_node(KEY_INF_MAX, NULL);
x->next = y;
y->prev = x;
sl->topleft = x;
sl->bottomleft = x;
sl->topright = y;
sl->bottomright = y;
sl->maxlevel = 0;
}
void _sl_add_level(slist *sl)
{
sl_node *x = _sl_create_node(KEY_INF_MIN, NULL);
sl_node *y = _sl_create_node(KEY_INF_MAX, NULL);
x->next = y;
y->prev = x;
x->below = sl->topleft;
y->below = sl->topright;
sl->topleft->above = x;
sl->topright->above = y;
sl->topleft = x;
sl->topright = y;
++sl->maxlevel;
}
void sl_free(slist *sl)
{
sl_node *foo;
sl_node *x;
sl_node *y;
for (foo = sl->bottomleft; foo != NULL;) {
x = foo;
foo = foo->next;
while (x != NULL) {
y = x;
x = x->above;
free(y->data);
free(y);
}
}
}
void _print_key(int key)
{
if (key == KEY_INF_MIN) {
debug("-INF -> ");
} else if (key == KEY_INF_MAX) {
debug("+INF -> ");
} else {
debug("%d -> ", key);
}
}
void _sl_println()
{
int i;
for (i = 0; i < 79; ++i) {
debug("-");
}
debug("\n");
}
void sl_print(const slist *sl)
{
sl_node *foo;
sl_node *x;
int level = sl->maxlevel;
_sl_println();
for (foo = sl->topleft; foo != NULL; foo = foo->below, --level) {
debug("level %d: ", level);
for (x = foo; x != NULL; x = x->next) {
_print_key(x->key);
}
debug("\n");
}
_sl_println();
debug("from below to above:\n");
for (foo = sl->bottomleft; foo != NULL; foo = foo->next) {
for (x = foo; x != NULL; x = x->above) {
_print_key(x->key);
}
debug("\n");
}
_sl_println();
}
#define HEAD 1
#define TAIL 0
int _toss_coin(int maxlevel) {
int i;
int x;
i = 0;
while(1) {
x = random() & 0x1;
if (x == TAIL) {
break;
}
++i;
/* inc level only by one at one iter */
if (i == maxlevel + 1) {
break;
}
};
return i;
}
/*
* Clean top levels with only INFINITY nodes until only one such
* level exists.
*/
void _sl_clean_top(slist *sl)
{
sl_node *foo;
for (foo = sl->topleft; foo->below != NULL; foo = foo->below) {
if (foo->next->key == KEY_INF_MAX
&& foo->below->next->key == KEY_INF_MAX) {
sl->topleft = foo->below;
sl->topright = foo->below->next;
sl->topleft->above = NULL;
sl->topright->above = NULL;
--sl->maxlevel;
free(foo->data);
free(foo->next);
free(foo);
debug("cleaned one level\n");
}
}
}
int sl_add(slist *sl, int key, void *data)
{
sl_node *foo;
sl_node *x;
int i;
int k;
int level;
sl_node **update;
int res;
if (key == KEY_INF_MIN || key == KEY_INF_MAX) {
return SL_ADD_INV;
}
i = _toss_coin(sl->maxlevel);
debug("toss coin result: %d\n", i);
if (i >= sl->maxlevel) {
/* add one more level */
_sl_add_level(sl);
debug("added level\n");
}
update = (sl_node **) xmalloc(sizeof(sl_node *) * (sl->maxlevel + 1));
bzero(update, sizeof(sl_node *) * (sl->maxlevel + 1));
level = sl->maxlevel;
foo = sl->topleft;
while (1) {
while (key >= foo->next->key) {
foo = foo->next;
}
if (foo->below == NULL) {
break;
}
update[level--] = foo;
foo = foo->below;
}
update[level] = foo;
debug("search finished at key: %d\n", foo->key);
debug("update list keys:\n");
for (k = 0; k <= sl->maxlevel; ++k) {
if (update[k] != 0) {
debug("%d\n", update[k]->key);
}
}
debug("adding\n");
if (foo->key == key) {
res = SL_ADD_SAME;
debug("key exists\n");
do {
foo->data = data;
foo = foo->above;
} while (foo != NULL);
} else {
res = SL_ADD_NEW;
debug("new key\n");
while (level <= i) {
x = _sl_create_node(key, data);
x->next = update[level]->next;
update[level]->next->prev = x;
x->prev = update[level];
update[level]->next = x;
if (level > 0) {
x->below = update[level - 1]->next;
update[level - 1]->next->above = x;
}
++level;
}
}
_sl_clean_top(sl);
free(update);
return res;
}
sl_node *sl_find(slist *sl, int key)
{
sl_node *foo;
foo = sl->topleft;
while (1) {
while (key >= foo->next->key) {
foo = foo->next;
}
if (foo->below == NULL) {
break;
}
foo = foo->below;
}
if (foo->key != key) {
foo = NULL;
}
return foo;
}
int sl_remove(slist *sl, int key)
{
sl_node *foo;
sl_node *x;
int result;
foo = sl->topleft;
while (1) {
while (key >= foo->next->key) {
foo = foo->next;
}
if (foo->below == NULL) {
break;
}
foo = foo->below;
}
if (foo->key == key) {
result = 1;
while (foo != NULL) {
foo->prev->next = foo->next;
foo->next->prev = foo->prev;
free(foo->data);
x = foo;
foo = foo->above;
free(x);
}
_sl_clean_top(sl);
} else {
result = 0;
}
return result;
}

63
skiplist.h Normal file
View file

@ -0,0 +1,63 @@
#ifndef __SKIPLIST
#define __SKIPLIST
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#define KEY_INF_MIN INT_MIN /* -INFINITY */
#define KEY_INF_MAX INT_MAX /* +INFINITY */
#define SL_ADD_NEW 1 /* added new key */
#define SL_ADD_SAME 0 /* added existing key */
#define SL_ADD_INV -1 /* added invalid key (+-INFINITY) */
/* skip list node */
typedef struct skiplist_node {
int key;
void *data;
struct skiplist_node *next;
struct skiplist_node *prev;
struct skiplist_node *below;
struct skiplist_node *above;
} sl_node;
/* skiplist object */
typedef struct skiplist {
sl_node *topleft;
sl_node *bottomleft;
sl_node *topright;
sl_node *bottomright;
int maxlevel;
} slist;
/*
* Initialize empty skip list.
*/
void sl_init(slist *sl);
/*
* Free skip list memory. After free list is not initialized
* for subsequent use.
*/
void sl_free(slist *sl);
/*
* Print skip list level by level and in down to up form.
*/
void sl_print(const slist *sl);
/*
* Add new key with data into skip list.
*/
int sl_add(slist *sl, int key, void *data);
/*
* Find node in skip list with given key.
* If key is not found returns NULL.
*/
sl_node *sl_find(slist *sl, int key);
/*
* Remove node from skip list with given key.
* If key is found and removed return 1, otherwise 0.
*/
int sl_remove(slist *sl, int key);
#endif

45
x.c Normal file
View file

@ -0,0 +1,45 @@
#include "x.h"
extern int dodebug;
static void _log_stderr(const char *fmt, va_list ap)
{
char buf[MAXLINE];
vsnprintf(buf, MAXLINE-1, fmt, ap);
fflush(stdout);
fputs(buf, stderr);
fflush(stderr);
}
void fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_log_stderr(fmt, ap);
va_end(ap);
exit(1);
}
void debug(const char *fmt, ...)
{
va_list ap;
if (dodebug) {
va_start(ap, fmt);
_log_stderr(fmt, ap);
va_end(ap);
}
}
void *xmalloc(size_t size)
{
void *foo = malloc(size);
if (foo == NULL) {
fatal("Not enough memory\n");
}
return foo;
}

18
x.h Normal file
View file

@ -0,0 +1,18 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define MAXLINE 1024
/*
* Print message and exit.
*/
void fatal(const char *fmt, ...);
/*
* malloc, if failed then fatal exit.
*/
void *xmalloc(size_t size);
/*
* Print debug message if debug is enabled.
*/
void debug(const char *fmt, ...);