diff --git a/main.c b/main.c index 15cfde7..9d438b0 100644 --- a/main.c +++ b/main.c @@ -76,6 +76,7 @@ int main(int argc, char **argv) key = random() % KEYCNT; keys[i] = key; res = sl_add(&sl, key, NULL); + sl_stat_print(&sl); switch(res) { case SL_ADD_NEW: ++cntnew; @@ -88,7 +89,8 @@ int main(int argc, char **argv) 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; sl_print(&sl); dodebug = 0; @@ -96,6 +98,7 @@ int main(int argc, char **argv) for (i = 0; i < KEYCNT; ++i) { key = keys[i]; x = sl_find(&sl, key); + sl_stat_print(&sl); if (!x) { failed = 1; break; @@ -108,6 +111,7 @@ int main(int argc, char **argv) for (i = 0; i < KEYCNT; ++i) { key = keys[i]; res = sl_remove(&sl, key); + sl_stat_print(&sl); switch (res) { case 0: ++cntsame; @@ -126,7 +130,11 @@ int main(int argc, char **argv) if (failed) { 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); return 0; diff --git a/skiplist.c b/skiplist.c index 0060650..b8549d3 100644 --- a/skiplist.c +++ b/skiplist.c @@ -27,6 +27,21 @@ void sl_init(slist *sl) sl->bottomright = y; 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) @@ -68,11 +83,11 @@ void sl_free(slist *sl) void _print_key(int key) { if (key == KEY_INF_MIN) { - debug("-INF -> "); + print("-INF -> "); } else if (key == KEY_INF_MAX) { - debug("+INF -> "); + print("+INF -> "); } else { - debug("%d -> ", key); + print("%d -> ", key); } } @@ -81,9 +96,9 @@ void _sl_println() int i; for (i = 0; i < 79; ++i) { - debug("-"); + print("-"); } - debug("\n"); + print("\n"); } void sl_print(const slist *sl) @@ -93,20 +108,21 @@ void sl_print(const slist *sl) int level = sl->maxlevel; _sl_println(); + print("from top to bottom:\n"); 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) { _print_key(x->key); } - debug("\n"); + print("\n"); } _sl_println(); - debug("from below to above:\n"); + print("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"); + print("\n"); } _sl_println(); } @@ -201,10 +217,15 @@ int sl_add(slist *sl, int key, void *data) bzero(update, sizeof(sl_node *) * (sl->maxlevel + 1)); level = sl->maxlevel; + ++sl->stat.addnum; foo = sl->topleft; + ++sl->stat.addcnt; + sl->stat.curradd = 1; while (1) { while (key >= foo->next->key) { foo = foo->next; + ++sl->stat.addcnt; + ++sl->stat.curradd; } if (foo->below == NULL) { break; @@ -214,7 +235,10 @@ int sl_add(slist *sl, int key, void *data) */ update[level--] = foo; foo = foo->below; + ++sl->stat.addcnt; + ++sl->stat.curradd; } + sl->stat.addcntmax = max(sl->stat.addcntmax, sl->stat.curradd); update[level] = foo; debug("search finished at key: %d\n", foo->key); @@ -248,6 +272,10 @@ int sl_add(slist *sl, int key, void *data) } ++level; } + ++sl->len; + if (sl->len > sl->stat.maxlen) { + sl->stat.maxlen = sl->len; + } } _sl_clean_top(sl); free(update); @@ -268,15 +296,23 @@ sl_node *sl_find(slist *sl, int key) sl_node *foo; foo = sl->topleft; + sl->stat.currsrch = 1; + ++sl->stat.srchcnt; + ++sl->stat.srchnum; while (1) { while (key >= foo->next->key) { foo = foo->next; + ++sl->stat.srchcnt; + ++sl->stat.currsrch; } if (foo->below == NULL) { break; } foo = foo->below; + ++sl->stat.srchcnt; + ++sl->stat.currsrch; } + sl->stat.srchcntmax = max(sl->stat.srchcntmax, sl->stat.currsrch); if (foo->key != key) { foo = NULL; @@ -296,15 +332,23 @@ int sl_remove(slist *sl, int key) int result; foo = sl->topleft; + sl->stat.currrm = 1; + ++sl->stat.rmcnt; + ++sl->stat.rmnum; while (1) { while (key >= foo->next->key) { foo = foo->next; + ++sl->stat.rmcnt; + ++sl->stat.currrm; } if (foo->below == NULL) { break; } foo = foo->below; + ++sl->stat.rmcnt; + ++sl->stat.currrm; } + sl->stat.rmcntmax = max(sl->stat.rmcntmax, sl->stat.currrm); if (foo->key == key) { result = 1; @@ -317,6 +361,7 @@ int sl_remove(slist *sl, int key) foo = foo->above; free(x); } + --sl->len; _sl_clean_top(sl); } else { @@ -325,3 +370,44 @@ int sl_remove(slist *sl, int key) 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); +} diff --git a/skiplist.h b/skiplist.h index 301c8ff..865944b 100644 --- a/skiplist.h +++ b/skiplist.h @@ -4,6 +4,7 @@ #include #include #include +#include #define KEY_INF_MIN INT_MIN /* -INFINITY */ #define KEY_INF_MAX INT_MAX /* +INFINITY */ @@ -12,6 +13,8 @@ #define SL_ADD_SAME 0 /* added existing key */ #define SL_ADD_INV -1 /* added invalid key (+-INFINITY) */ +#define max(x, y) ((x) > (y) ? (x) : (y)) + /* skip list node */ typedef struct skiplist_node { int key; @@ -22,6 +25,27 @@ typedef struct skiplist_node { struct skiplist_node *above; } 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 */ typedef struct skiplist { sl_node *topleft; @@ -29,6 +53,8 @@ typedef struct skiplist { sl_node *topright; sl_node *bottomright; int maxlevel; + size_t len; + slstat stat; } slist; /* @@ -58,6 +84,9 @@ sl_node *sl_find(slist *sl, int key); * If key is found and removed return 1, otherwise 0. */ int sl_remove(slist *sl, int key); - +/* + * Print current statistics. + */ +void sl_stat_print(const slist *sl); #endif diff --git a/x.c b/x.c index c45282b..84e9cba 100644 --- a/x.c +++ b/x.c @@ -2,14 +2,14 @@ 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]; vsnprintf(buf, MAXLINE-1, fmt, ap); - fflush(stdout); - fputs(buf, stderr); - fflush(stderr); + fflush(f); + fputs(buf, f); + fflush(f); } void fatal(const char *fmt, ...) @@ -17,7 +17,7 @@ void fatal(const char *fmt, ...) va_list ap; va_start(ap, fmt); - _log_stderr(fmt, ap); + _log_stderr(stderr, fmt, ap); va_end(ap); exit(1); } @@ -28,11 +28,20 @@ void debug(const char *fmt, ...) if (dodebug) { va_start(ap, fmt); - _log_stderr(fmt, ap); + _log_stderr(stderr, fmt, 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 *foo = malloc(size); diff --git a/x.h b/x.h index e7c3024..ff4e4f6 100644 --- a/x.h +++ b/x.h @@ -16,3 +16,7 @@ void *xmalloc(size_t size); * Print debug message if debug is enabled. */ void debug(const char *fmt, ...); +/* + * Print to stdout. + */ +void print(const char *fmt, ...);