diff --git a/skip_list.c b/skip_list.c new file mode 100644 index 000000000..6d1cfb867 --- /dev/null +++ b/skip_list.c @@ -0,0 +1,77 @@ +#include "skip_list.h" +#include + +static int xRandomLevel(void) { + int level = 1; + while ((rand() & 0x1) && level < SKIP_LIST_MAX_LEVEL) + level++; + return level; +} + +void vSkipListInit(SkipList_t *list) { + list->level = 1; + list->header = (SkipListNode_t *)calloc(1, sizeof(SkipListNode_t)); + for (int i = 0; i < SKIP_LIST_MAX_LEVEL; i++) + list->header->forward[i] = NULL; +} + +void vSkipListInsert(SkipList_t *list, TickType_t key, void *value) { + SkipListNode_t *update[SKIP_LIST_MAX_LEVEL]; + SkipListNode_t *x = list->header; + for (int i = list->level - 1; i >= 0; i--) { + while (x->forward[i] && x->forward[i]->key < key) + x = x->forward[i]; + update[i] = x; + } + x = x->forward[0]; + if (x && x->key == key) { + x->value = value; + return; + } + int lvl = xRandomLevel(); + if (lvl > list->level) { + for (int i = list->level; i < lvl; i++) + update[i] = list->header; + list->level = lvl; + } + x = (SkipListNode_t *)calloc(1, sizeof(SkipListNode_t)); + x->key = key; + x->value = value; + for (int i = 0; i < lvl; i++) { + x->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = x; + } +} + +void vSkipListRemove(SkipList_t *list, TickType_t key) { + SkipListNode_t *update[SKIP_LIST_MAX_LEVEL]; + SkipListNode_t *x = list->header; + for (int i = list->level - 1; i >= 0; i--) { + while (x->forward[i] && x->forward[i]->key < key) + x = x->forward[i]; + update[i] = x; + } + x = x->forward[0]; + if (x && x->key == key) { + for (int i = 0; i < list->level; i++) { + if (update[i]->forward[i] != x) + break; + update[i]->forward[i] = x->forward[i]; + } + free(x); + while (list->level > 1 && list->header->forward[list->level - 1] == NULL) + list->level--; + } +} + +void *pvSkipListSearch(SkipList_t *list, TickType_t key) { + SkipListNode_t *x = list->header; + for (int i = list->level - 1; i >= 0; i--) { + while (x->forward[i] && x->forward[i]->key < key) + x = x->forward[i]; + } + x = x->forward[0]; + if (x && x->key == key) + return x->value; + return NULL; +} diff --git a/skip_list.h b/skip_list.h new file mode 100644 index 000000000..737855cff --- /dev/null +++ b/skip_list.h @@ -0,0 +1,32 @@ +#ifndef FREERTOS_SKIP_LIST_H +#define FREERTOS_SKIP_LIST_H + +#include +#include + +#ifndef TickType_t +typedef unsigned int TickType_t; +#endif + +#ifndef SKIP_LIST_MAX_LEVEL +#define SKIP_LIST_MAX_LEVEL 4 // Tunable for memory/complexity tradeoff +#endif + +// Forward declaration +typedef struct SkipListNode { + TickType_t key; + void *value; + struct SkipListNode *forward[SKIP_LIST_MAX_LEVEL]; +} SkipListNode_t; + +typedef struct SkipList { + SkipListNode_t *header; + int level; +} SkipList_t; + +void vSkipListInit(SkipList_t *list); +void vSkipListInsert(SkipList_t *list, TickType_t key, void *value); +void vSkipListRemove(SkipList_t *list, TickType_t key); +void *pvSkipListSearch(SkipList_t *list, TickType_t key); + +#endif // FREERTOS_SKIP_LIST_H diff --git a/test_skip_list.c b/test_skip_list.c new file mode 100644 index 000000000..c141ea00d --- /dev/null +++ b/test_skip_list.c @@ -0,0 +1,62 @@ +#include +#include +#include "skip_list.h" + +void print_skip_list(SkipList_t *list) { + printf("Skip List: "); + SkipListNode_t *node = list->header->forward[0]; + while (node) { + printf("(%u, %p) ", node->key, node->value); + node = node->forward[0]; + } + printf("\n"); +} + +int main(void) { + SkipList_t list; + vSkipListInit(&list); + + // Insert test + printf("Inserting values...\n"); + for (TickType_t i = 10; i > 0; --i) { + int *val = (int *)malloc(sizeof(int)); + *val = i * 100; + vSkipListInsert(&list, i, val); + } + print_skip_list(&list); + + // Search test + printf("Searching for key 5...\n"); + int *found = (int *)pvSkipListSearch(&list, 5); + if (found) { + printf("Found key 5 with value %d\n", *found); + } else { + printf("Key 5 not found!\n"); + } + + printf("Searching for key 42...\n"); + found = (int *)pvSkipListSearch(&list, 42); + if (found) { + printf("Found key 42 with value %d\n", *found); + } else { + printf("Key 42 not found!\n"); + } + + // Remove test + printf("Removing key 5...\n"); + vSkipListRemove(&list, 5); + print_skip_list(&list); + found = (int *)pvSkipListSearch(&list, 5); + if (!found) { + printf("Key 5 successfully removed.\n"); + } + + // Cleanup + for (TickType_t i = 1; i <= 10; ++i) { + int *val = (int *)pvSkipListSearch(&list, i); + if (val) free(val); + } + // Free header node + free(list.header); + return 0; +} diff --git a/test_skip_list.exe b/test_skip_list.exe new file mode 100644 index 000000000..c1fb49fad Binary files /dev/null and b/test_skip_list.exe differ