Add list length member and simple statistics.
This commit is contained in:
parent
526617cfc9
commit
4f055d709e
5 changed files with 154 additions and 18 deletions
12
main.c
12
main.c
|
@ -76,6 +76,7 @@ int main(int argc, char **argv)
|
||||||
key = random() % KEYCNT;
|
key = random() % KEYCNT;
|
||||||
keys[i] = key;
|
keys[i] = key;
|
||||||
res = sl_add(&sl, key, NULL);
|
res = sl_add(&sl, key, NULL);
|
||||||
|
sl_stat_print(&sl);
|
||||||
switch(res) {
|
switch(res) {
|
||||||
case SL_ADD_NEW:
|
case SL_ADD_NEW:
|
||||||
++cntnew;
|
++cntnew;
|
||||||
|
@ -88,7 +89,8 @@ int main(int argc, char **argv)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("added %d new keys, %d same keys\n", cntnew, cntsame);
|
printf("added %d new keys, %d same keys, list len: %lu\n",
|
||||||
|
cntnew, cntsame, sl.len);
|
||||||
dodebug = 1;
|
dodebug = 1;
|
||||||
sl_print(&sl);
|
sl_print(&sl);
|
||||||
dodebug = 0;
|
dodebug = 0;
|
||||||
|
@ -96,6 +98,7 @@ int main(int argc, char **argv)
|
||||||
for (i = 0; i < KEYCNT; ++i) {
|
for (i = 0; i < KEYCNT; ++i) {
|
||||||
key = keys[i];
|
key = keys[i];
|
||||||
x = sl_find(&sl, key);
|
x = sl_find(&sl, key);
|
||||||
|
sl_stat_print(&sl);
|
||||||
if (!x) {
|
if (!x) {
|
||||||
failed = 1;
|
failed = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -108,6 +111,7 @@ int main(int argc, char **argv)
|
||||||
for (i = 0; i < KEYCNT; ++i) {
|
for (i = 0; i < KEYCNT; ++i) {
|
||||||
key = keys[i];
|
key = keys[i];
|
||||||
res = sl_remove(&sl, key);
|
res = sl_remove(&sl, key);
|
||||||
|
sl_stat_print(&sl);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case 0:
|
case 0:
|
||||||
++cntsame;
|
++cntsame;
|
||||||
|
@ -126,7 +130,11 @@ int main(int argc, char **argv)
|
||||||
if (failed) {
|
if (failed) {
|
||||||
fatal("remove failed, report bug\n");
|
fatal("remove failed, report bug\n");
|
||||||
}
|
}
|
||||||
printf("removed %d new keys, %d same keys\n", cntnew, cntsame);
|
dodebug = 1;
|
||||||
|
sl_print(&sl);
|
||||||
|
dodebug = 0;
|
||||||
|
printf("removed %d keys, %d same keys, list len: %lu\n",
|
||||||
|
cntnew, cntsame, sl.len);
|
||||||
sl_free(&sl);
|
sl_free(&sl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
104
skiplist.c
104
skiplist.c
|
@ -27,6 +27,21 @@ void sl_init(slist *sl)
|
||||||
sl->bottomright = y;
|
sl->bottomright = y;
|
||||||
|
|
||||||
sl->maxlevel = 0;
|
sl->maxlevel = 0;
|
||||||
|
sl->len = 2; /* -INF and +INF */
|
||||||
|
|
||||||
|
sl->stat.srchcnt = 0;
|
||||||
|
sl->stat.rmcnt = 0;
|
||||||
|
sl->stat.addcnt = 0;
|
||||||
|
sl->stat.srchnum = 0;
|
||||||
|
sl->stat.rmnum = 0;
|
||||||
|
sl->stat.addnum = 0;
|
||||||
|
sl->stat.maxlen = sl->len;
|
||||||
|
sl->stat.currsrch = 0;
|
||||||
|
sl->stat.currrm = 0;
|
||||||
|
sl->stat.curradd = 0;
|
||||||
|
sl->stat.srchcntmax = 0;
|
||||||
|
sl->stat.rmcntmax = 0;
|
||||||
|
sl->stat.addcntmax = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _sl_add_level(slist *sl)
|
void _sl_add_level(slist *sl)
|
||||||
|
@ -68,11 +83,11 @@ void sl_free(slist *sl)
|
||||||
void _print_key(int key)
|
void _print_key(int key)
|
||||||
{
|
{
|
||||||
if (key == KEY_INF_MIN) {
|
if (key == KEY_INF_MIN) {
|
||||||
debug("-INF -> ");
|
print("-INF -> ");
|
||||||
} else if (key == KEY_INF_MAX) {
|
} else if (key == KEY_INF_MAX) {
|
||||||
debug("+INF -> ");
|
print("+INF -> ");
|
||||||
} else {
|
} else {
|
||||||
debug("%d -> ", key);
|
print("%d -> ", key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +96,9 @@ void _sl_println()
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < 79; ++i) {
|
for (i = 0; i < 79; ++i) {
|
||||||
debug("-");
|
print("-");
|
||||||
}
|
}
|
||||||
debug("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void sl_print(const slist *sl)
|
void sl_print(const slist *sl)
|
||||||
|
@ -93,20 +108,21 @@ void sl_print(const slist *sl)
|
||||||
int level = sl->maxlevel;
|
int level = sl->maxlevel;
|
||||||
|
|
||||||
_sl_println();
|
_sl_println();
|
||||||
|
print("from top to bottom:\n");
|
||||||
for (foo = sl->topleft; foo != NULL; foo = foo->below, --level) {
|
for (foo = sl->topleft; foo != NULL; foo = foo->below, --level) {
|
||||||
debug("level %d: ", level);
|
print("level %d: ", level);
|
||||||
for (x = foo; x != NULL; x = x->next) {
|
for (x = foo; x != NULL; x = x->next) {
|
||||||
_print_key(x->key);
|
_print_key(x->key);
|
||||||
}
|
}
|
||||||
debug("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
_sl_println();
|
_sl_println();
|
||||||
debug("from below to above:\n");
|
print("from below to above:\n");
|
||||||
for (foo = sl->bottomleft; foo != NULL; foo = foo->next) {
|
for (foo = sl->bottomleft; foo != NULL; foo = foo->next) {
|
||||||
for (x = foo; x != NULL; x = x->above) {
|
for (x = foo; x != NULL; x = x->above) {
|
||||||
_print_key(x->key);
|
_print_key(x->key);
|
||||||
}
|
}
|
||||||
debug("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
_sl_println();
|
_sl_println();
|
||||||
}
|
}
|
||||||
|
@ -201,10 +217,15 @@ int sl_add(slist *sl, int key, void *data)
|
||||||
bzero(update, sizeof(sl_node *) * (sl->maxlevel + 1));
|
bzero(update, sizeof(sl_node *) * (sl->maxlevel + 1));
|
||||||
level = sl->maxlevel;
|
level = sl->maxlevel;
|
||||||
|
|
||||||
|
++sl->stat.addnum;
|
||||||
foo = sl->topleft;
|
foo = sl->topleft;
|
||||||
|
++sl->stat.addcnt;
|
||||||
|
sl->stat.curradd = 1;
|
||||||
while (1) {
|
while (1) {
|
||||||
while (key >= foo->next->key) {
|
while (key >= foo->next->key) {
|
||||||
foo = foo->next;
|
foo = foo->next;
|
||||||
|
++sl->stat.addcnt;
|
||||||
|
++sl->stat.curradd;
|
||||||
}
|
}
|
||||||
if (foo->below == NULL) {
|
if (foo->below == NULL) {
|
||||||
break;
|
break;
|
||||||
|
@ -214,7 +235,10 @@ int sl_add(slist *sl, int key, void *data)
|
||||||
*/
|
*/
|
||||||
update[level--] = foo;
|
update[level--] = foo;
|
||||||
foo = foo->below;
|
foo = foo->below;
|
||||||
|
++sl->stat.addcnt;
|
||||||
|
++sl->stat.curradd;
|
||||||
}
|
}
|
||||||
|
sl->stat.addcntmax = max(sl->stat.addcntmax, sl->stat.curradd);
|
||||||
update[level] = foo;
|
update[level] = foo;
|
||||||
|
|
||||||
debug("search finished at key: %d\n", foo->key);
|
debug("search finished at key: %d\n", foo->key);
|
||||||
|
@ -248,6 +272,10 @@ int sl_add(slist *sl, int key, void *data)
|
||||||
}
|
}
|
||||||
++level;
|
++level;
|
||||||
}
|
}
|
||||||
|
++sl->len;
|
||||||
|
if (sl->len > sl->stat.maxlen) {
|
||||||
|
sl->stat.maxlen = sl->len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_sl_clean_top(sl);
|
_sl_clean_top(sl);
|
||||||
free(update);
|
free(update);
|
||||||
|
@ -268,15 +296,23 @@ sl_node *sl_find(slist *sl, int key)
|
||||||
sl_node *foo;
|
sl_node *foo;
|
||||||
|
|
||||||
foo = sl->topleft;
|
foo = sl->topleft;
|
||||||
|
sl->stat.currsrch = 1;
|
||||||
|
++sl->stat.srchcnt;
|
||||||
|
++sl->stat.srchnum;
|
||||||
while (1) {
|
while (1) {
|
||||||
while (key >= foo->next->key) {
|
while (key >= foo->next->key) {
|
||||||
foo = foo->next;
|
foo = foo->next;
|
||||||
|
++sl->stat.srchcnt;
|
||||||
|
++sl->stat.currsrch;
|
||||||
}
|
}
|
||||||
if (foo->below == NULL) {
|
if (foo->below == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
foo = foo->below;
|
foo = foo->below;
|
||||||
|
++sl->stat.srchcnt;
|
||||||
|
++sl->stat.currsrch;
|
||||||
}
|
}
|
||||||
|
sl->stat.srchcntmax = max(sl->stat.srchcntmax, sl->stat.currsrch);
|
||||||
|
|
||||||
if (foo->key != key) {
|
if (foo->key != key) {
|
||||||
foo = NULL;
|
foo = NULL;
|
||||||
|
@ -296,15 +332,23 @@ int sl_remove(slist *sl, int key)
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
foo = sl->topleft;
|
foo = sl->topleft;
|
||||||
|
sl->stat.currrm = 1;
|
||||||
|
++sl->stat.rmcnt;
|
||||||
|
++sl->stat.rmnum;
|
||||||
while (1) {
|
while (1) {
|
||||||
while (key >= foo->next->key) {
|
while (key >= foo->next->key) {
|
||||||
foo = foo->next;
|
foo = foo->next;
|
||||||
|
++sl->stat.rmcnt;
|
||||||
|
++sl->stat.currrm;
|
||||||
}
|
}
|
||||||
if (foo->below == NULL) {
|
if (foo->below == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
foo = foo->below;
|
foo = foo->below;
|
||||||
|
++sl->stat.rmcnt;
|
||||||
|
++sl->stat.currrm;
|
||||||
}
|
}
|
||||||
|
sl->stat.rmcntmax = max(sl->stat.rmcntmax, sl->stat.currrm);
|
||||||
|
|
||||||
if (foo->key == key) {
|
if (foo->key == key) {
|
||||||
result = 1;
|
result = 1;
|
||||||
|
@ -317,6 +361,7 @@ int sl_remove(slist *sl, int key)
|
||||||
foo = foo->above;
|
foo = foo->above;
|
||||||
free(x);
|
free(x);
|
||||||
}
|
}
|
||||||
|
--sl->len;
|
||||||
|
|
||||||
_sl_clean_top(sl);
|
_sl_clean_top(sl);
|
||||||
} else {
|
} else {
|
||||||
|
@ -325,3 +370,44 @@ int sl_remove(slist *sl, int key)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sl_stat_print(const slist *sl)
|
||||||
|
{
|
||||||
|
size_t avgsrch;
|
||||||
|
size_t avgadd;
|
||||||
|
size_t avgrm;
|
||||||
|
|
||||||
|
_sl_println();
|
||||||
|
print("skiplist statistics:\n");
|
||||||
|
print("current len: %lu\n", sl->len);
|
||||||
|
|
||||||
|
print("search count: %lu\n", sl->stat.srchcnt);
|
||||||
|
print("add count: %lu\n", sl->stat.addcnt);
|
||||||
|
print("remove count: %lu\n", sl->stat.rmcnt);
|
||||||
|
|
||||||
|
print("search num: %lu\n", sl->stat.srchnum);
|
||||||
|
print("add num: %lu\n", sl->stat.addnum);
|
||||||
|
print("remove num: %lu\n", sl->stat.rmnum);
|
||||||
|
|
||||||
|
print("current search count: %lu\n", sl->stat.currsrch);
|
||||||
|
print("current add count: %lu\n", sl->stat.curradd);
|
||||||
|
print("current remove count: %lu\n", sl->stat.currrm);
|
||||||
|
|
||||||
|
if (sl->stat.srchnum != 0) {
|
||||||
|
avgsrch = sl->stat.srchcnt / sl->stat.srchnum;
|
||||||
|
print("average search count: %lu\n", avgsrch);
|
||||||
|
}
|
||||||
|
if (sl->stat.addnum != 0) {
|
||||||
|
avgadd = sl->stat.addcnt / sl->stat.addnum;
|
||||||
|
print("average add count: %lu\n", avgadd);
|
||||||
|
}
|
||||||
|
if (sl->stat.rmnum != 0) {
|
||||||
|
avgrm = sl->stat.rmcnt / sl->stat.rmnum;
|
||||||
|
print("average remove count: %lu\n", avgrm);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("maxlen: %lu\n", sl->stat.maxlen);
|
||||||
|
print("max search count: %lu\n", sl->stat.srchcntmax);
|
||||||
|
print("max add count: %lu\n", sl->stat.addcntmax);
|
||||||
|
print("max remove count: %lu\n", sl->stat.rmcntmax);
|
||||||
|
}
|
||||||
|
|
31
skiplist.h
31
skiplist.h
|
@ -4,6 +4,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define KEY_INF_MIN INT_MIN /* -INFINITY */
|
#define KEY_INF_MIN INT_MIN /* -INFINITY */
|
||||||
#define KEY_INF_MAX INT_MAX /* +INFINITY */
|
#define KEY_INF_MAX INT_MAX /* +INFINITY */
|
||||||
|
@ -12,6 +13,8 @@
|
||||||
#define SL_ADD_SAME 0 /* added existing key */
|
#define SL_ADD_SAME 0 /* added existing key */
|
||||||
#define SL_ADD_INV -1 /* added invalid key (+-INFINITY) */
|
#define SL_ADD_INV -1 /* added invalid key (+-INFINITY) */
|
||||||
|
|
||||||
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
||||||
/* skip list node */
|
/* skip list node */
|
||||||
typedef struct skiplist_node {
|
typedef struct skiplist_node {
|
||||||
int key;
|
int key;
|
||||||
|
@ -22,6 +25,27 @@ typedef struct skiplist_node {
|
||||||
struct skiplist_node *above;
|
struct skiplist_node *above;
|
||||||
} sl_node;
|
} sl_node;
|
||||||
|
|
||||||
|
/* skiplist statistics */
|
||||||
|
typedef struct skiplist_stats {
|
||||||
|
size_t srchcnt; /* count nodes visited while searching */
|
||||||
|
size_t rmcnt; /* count nodes visited while removing */
|
||||||
|
size_t addcnt; /* count nodes visited while adding */
|
||||||
|
|
||||||
|
size_t srchnum; /* number of searches */
|
||||||
|
size_t rmnum; /* number of removals */
|
||||||
|
size_t addnum; /* number of additions */
|
||||||
|
|
||||||
|
size_t maxlen; /* maximum list len */
|
||||||
|
|
||||||
|
size_t currsrch; /* nodes visited for current search */
|
||||||
|
size_t currrm; /* nodes visited for current search */
|
||||||
|
size_t curradd; /* nodes visited for current search */
|
||||||
|
|
||||||
|
size_t srchcntmax; /* max nodes count visited while searching */
|
||||||
|
size_t rmcntmax; /* max nodes count visited while removing */
|
||||||
|
size_t addcntmax; /* max nodes count visited while adding */
|
||||||
|
} slstat;
|
||||||
|
|
||||||
/* skiplist object */
|
/* skiplist object */
|
||||||
typedef struct skiplist {
|
typedef struct skiplist {
|
||||||
sl_node *topleft;
|
sl_node *topleft;
|
||||||
|
@ -29,6 +53,8 @@ typedef struct skiplist {
|
||||||
sl_node *topright;
|
sl_node *topright;
|
||||||
sl_node *bottomright;
|
sl_node *bottomright;
|
||||||
int maxlevel;
|
int maxlevel;
|
||||||
|
size_t len;
|
||||||
|
slstat stat;
|
||||||
} slist;
|
} slist;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -58,6 +84,9 @@ sl_node *sl_find(slist *sl, int key);
|
||||||
* If key is found and removed return 1, otherwise 0.
|
* If key is found and removed return 1, otherwise 0.
|
||||||
*/
|
*/
|
||||||
int sl_remove(slist *sl, int key);
|
int sl_remove(slist *sl, int key);
|
||||||
|
/*
|
||||||
|
* Print current statistics.
|
||||||
|
*/
|
||||||
|
void sl_stat_print(const slist *sl);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
21
x.c
21
x.c
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
extern int dodebug;
|
extern int dodebug;
|
||||||
|
|
||||||
static void _log_stderr(const char *fmt, va_list ap)
|
static void _log_stderr(FILE *f, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
char buf[MAXLINE];
|
char buf[MAXLINE];
|
||||||
|
|
||||||
vsnprintf(buf, MAXLINE-1, fmt, ap);
|
vsnprintf(buf, MAXLINE-1, fmt, ap);
|
||||||
fflush(stdout);
|
fflush(f);
|
||||||
fputs(buf, stderr);
|
fputs(buf, f);
|
||||||
fflush(stderr);
|
fflush(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fatal(const char *fmt, ...)
|
void fatal(const char *fmt, ...)
|
||||||
|
@ -17,7 +17,7 @@ void fatal(const char *fmt, ...)
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_log_stderr(fmt, ap);
|
_log_stderr(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,20 @@ void debug(const char *fmt, ...)
|
||||||
|
|
||||||
if (dodebug) {
|
if (dodebug) {
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_log_stderr(fmt, ap);
|
_log_stderr(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_log_stderr(stdout, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
void *xmalloc(size_t size)
|
void *xmalloc(size_t size)
|
||||||
{
|
{
|
||||||
void *foo = malloc(size);
|
void *foo = malloc(size);
|
||||||
|
|
4
x.h
4
x.h
|
@ -16,3 +16,7 @@ void *xmalloc(size_t size);
|
||||||
* Print debug message if debug is enabled.
|
* Print debug message if debug is enabled.
|
||||||
*/
|
*/
|
||||||
void debug(const char *fmt, ...);
|
void debug(const char *fmt, ...);
|
||||||
|
/*
|
||||||
|
* Print to stdout.
|
||||||
|
*/
|
||||||
|
void print(const char *fmt, ...);
|
||||||
|
|
Loading…
Reference in a new issue