From 86be1e8de5c751ab4a01013926e7355fb0822799 Mon Sep 17 00:00:00 2001 From: Evan Burkey Date: Mon, 1 Feb 2021 14:06:37 -0800 Subject: [PATCH] init --- .gitignore | 1 + .idea/.gitignore | 8 +++ .idea/libfputs.iml | 2 + .idea/misc.xml | 4 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ CMakeLists.txt | 21 ++++++ LICENSE | 13 ++++ README.md | 3 + include/binarytree.h | 31 ++++++++ include/linkedlist.h | 30 ++++++++ include/set.h | 20 ++++++ include/stack.h | 14 ++++ src/binarytree.c | 163 +++++++++++++++++++++++++++++++++++++++++++ src/linkedlist.c | 122 ++++++++++++++++++++++++++++++++ src/set.c | 124 ++++++++++++++++++++++++++++++++ src/stack.c | 25 +++++++ tests/tests.c | 155 ++++++++++++++++++++++++++++++++++++++++ 18 files changed, 750 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/libfputs.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 include/binarytree.h create mode 100644 include/linkedlist.h create mode 100644 include/set.h create mode 100644 include/stack.h create mode 100644 src/binarytree.c create mode 100644 src/linkedlist.c create mode 100644 src/set.c create mode 100644 src/stack.c create mode 100644 tests/tests.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..374fe5c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +cmake* diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/libfputs.iml b/.idea/libfputs.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/libfputs.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2ff26f1 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..85189d1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.17) +project(flint C) + +set(CMAKE_C_STANDARD 99) +include_directories(include) + +set(SOURCES + src/linkedlist.c + src/set.c + src/stack.c + src/binarytree.c +) + +add_library(flint ${SOURCES}) + +if(${CMAKE_PROJECT_NAME} STREQUAL flint) + add_executable(tests tests/tests.c) + target_include_directories(tests PRIVATE include) + target_link_libraries(tests flint) +endif() + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5cf2a89 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2021 Evan Burkey + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..69b92c1 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# flint + +My personal library of common C data structures and algorithms. diff --git a/include/binarytree.h b/include/binarytree.h new file mode 100644 index 0000000..df78a23 --- /dev/null +++ b/include/binarytree.h @@ -0,0 +1,31 @@ +#ifndef LIBFLINT_BINARY_TREE_H +#define LIBFLINT_BINARY_TREE_H + +struct BinTreeNode { + void *data; + struct BinTreeNode *left; + struct BinTreeNode *right; +}; + +struct BinTree { + int size; + + int (*compare)(const void *a, const void *b); + void (*destroy)(void *data); + + struct BinTreeNode *root; +}; + +void bintree_init(struct BinTree *tree, void (*destroy)(void *data)); +void bintree_destroy(struct BinTree *tree); +int bintree_ins_left(struct BinTree *tree, struct BinTreeNode *node, void *data); +int bintree_ins_right(struct BinTree *tree, struct BinTreeNode *node, void *data); +void bintree_rem_left(struct BinTree *tree, struct BinTreeNode *node); +void bintree_rem_right(struct BinTree *tree, struct BinTreeNode *node); +int bintree_merge(struct BinTree *merge, struct BinTree *left, struct BinTree *right, void *data); +void bintree_debug_print(struct BinTree *tree); + +#define bintree_is_eob(node) ((node) == NULL) +#define bintree_is_leaf(node) ((node)->left == NULL && (node)->right == NULL) + +#endif diff --git a/include/linkedlist.h b/include/linkedlist.h new file mode 100644 index 0000000..ab18e5d --- /dev/null +++ b/include/linkedlist.h @@ -0,0 +1,30 @@ +#ifndef LIBFLINT_LL_H +#define LIBFLINT_LL_H + +#include + +struct ListNode { + void* data; + struct ListNode* next; + struct ListNode* prev; +}; + +struct List { + size_t size; + + void (*destroy)(void* data); + int (*match)(const void* a, const void* b); + + struct ListNode* head; + struct ListNode* tail; +}; + +void ll_init(struct List* list, void (*destroy)(void *data)); +void ll_destroy(struct List* list); +int ll_ins_next(struct List* list, struct ListNode* node, const void* data); +int ll_ins_prev(struct List* list, struct ListNode* node, const void* data); +int ll_remove(struct List* list, struct ListNode* node, void** data); +int ll_remove_next(struct List* list, struct ListNode* node, void** data); +int ll_remove_prev(struct List* list, struct ListNode* node, void** data); + +#endif diff --git a/include/set.h b/include/set.h new file mode 100644 index 0000000..08bfcc5 --- /dev/null +++ b/include/set.h @@ -0,0 +1,20 @@ +#ifndef LIBFLINT_SET_H +#define LIBFLINT_SET_H + +#include "linkedlist.h" + +#define Set List + +void set_init(struct Set* set, int (*match)(const void* a, const void* b), + void (*destroy)(void* data)); +void set_destroy(struct Set* set); +int set_insert(struct Set* set, const void* data); +int set_remove(struct Set* set, void** data); +int set_union(struct Set* setu, const struct Set* a, const struct Set* b); +int set_intersection(struct Set* seti, const struct Set* a, const struct Set* b); +int set_difference(struct Set* setd, const struct Set* a, const struct Set* b); +int set_is_member(const struct Set* set, const void* data); +int set_is_subset(const struct Set* a, const struct Set* b); +int set_is_equal(const struct Set* a, const struct Set* b); + +#endif diff --git a/include/stack.h b/include/stack.h new file mode 100644 index 0000000..e0f4919 --- /dev/null +++ b/include/stack.h @@ -0,0 +1,14 @@ +#ifndef LIBFLINT_STACK_H +#define LIBFLINT_STACK_H + +#include "linkedlist.h" + +#define Stack List + +void stack_init(struct Stack* stack, void (*destroy)(void* data)); +void stack_destroy(struct Stack* stack); +int stack_push(struct Stack* stack, void *data); +void *stack_peek(struct Stack *stack); +int stack_pop(struct Stack *stack, void **data); + +#endif diff --git a/src/binarytree.c b/src/binarytree.c new file mode 100644 index 0000000..529fd45 --- /dev/null +++ b/src/binarytree.c @@ -0,0 +1,163 @@ +#include +#include +#include + +#include "binarytree.h" + +void bintree_init(struct BinTree *tree, void (*destroy)(void *data)) { + tree->size = 0; + tree->destroy = destroy; + tree->compare = NULL; + tree->root = NULL; +} + +void bintree_destroy(struct BinTree *tree) { + bintree_rem_left(tree, NULL); + memset(tree, 0, sizeof(struct BinTree)); +} + +int bintree_ins_left(struct BinTree *tree, struct BinTreeNode *node, void *data) { + struct BinTreeNode *new_node; + struct BinTreeNode **pos; + + if (node == NULL) { + if (tree->size > 0) { + return 1; + } + pos = &tree->root; + } else { + if (node->left != NULL) { + return -1; + } + pos = &node->left; + } + + if ((new_node = malloc(sizeof(struct BinTreeNode))) == NULL) { + return 2; + } + + new_node->data = data; + new_node->left = NULL; + new_node->right = NULL; + *pos = new_node; + + tree->size += 1; + return 0; +} + +int bintree_ins_right(struct BinTree *tree, struct BinTreeNode *node, void *data) { + struct BinTreeNode *new_node; + struct BinTreeNode **pos; + + if (node == NULL) { + if (tree->size > 0) { + return 1; + } + pos = &tree->root; + } else { + if (node->right != NULL) { + return -1; + } + pos = &node->right; + } + + if ((new_node = malloc(sizeof(struct BinTreeNode))) == NULL) { + return 2; + } + + new_node->data = data; + new_node->left = NULL; + new_node->right = NULL; + *pos = new_node; + + tree->size += 1; + return 0; +} + +void bintree_rem_left(struct BinTree *tree, struct BinTreeNode *node) { + if (tree->size == 0) { + return; + } + + struct BinTreeNode **pos; + if (node == NULL) { + pos = &tree->root; + } else { + pos = &node->left; + } + + if (*pos != NULL) { + bintree_rem_left(tree, *pos); + bintree_rem_right(tree, *pos); + if (tree->destroy != NULL) { + tree->destroy((*pos)->data); + } + free(*pos); + *pos = NULL; + tree->size -= 1; + } +} + +void bintree_rem_right(struct BinTree *tree, struct BinTreeNode *node) { + if (tree->size == 0) { + return; + } + + struct BinTreeNode **pos; + if (node == NULL) { + pos = &tree->root; + } else { + pos = &node->right; + } + + if (*pos != NULL) { + bintree_rem_left(tree, *pos); + bintree_rem_right(tree, *pos); + if (tree->destroy != NULL) { + tree->destroy((*pos)->data); + } + free(*pos); + *pos = NULL; + tree->size -= 1; + } +} + +int bintree_merge(struct BinTree *merge, struct BinTree *left, struct BinTree *right, void *data) { + bintree_init(merge, left->destroy); + if (bintree_ins_left(merge, NULL, data) != 0) { + bintree_destroy(merge); + return -1; + } + + merge->root->left = left->root; + merge->root->right = right->root; + + left->root = NULL; + left->size = 0; + right->root = NULL; + right->size = 0; + + return 0; +} + +void print_node(char* prefix, struct BinTreeNode *node, int is_left, void (*pfunc)(void* data)) { + if (node != NULL) { + printf("%s%s", prefix, (is_left ? "├──" : "└──" )); + pfunc(node->data); + char new_prefix[64]; + memset(new_prefix, 0, 64); + strcat(new_prefix, prefix); + strcat(new_prefix, (is_left == 1 ? "│ " : " ")); + print_node(new_prefix, node->left, 1, pfunc); + print_node(new_prefix, node->right, 0, pfunc); + } +} + +void bintree_debug_pfunc_int(void* data) { + int i = *((int*)data); + printf("%d\n", i); +} + +void bintree_debug_print(struct BinTree *tree) { + print_node("", tree->root, 0, bintree_debug_pfunc_int); +} diff --git a/src/linkedlist.c b/src/linkedlist.c new file mode 100644 index 0000000..48fdeda --- /dev/null +++ b/src/linkedlist.c @@ -0,0 +1,122 @@ +#include +#include + +#include "linkedlist.h" + +void ll_init(struct List* list, void (*destroy)(void *data)) { + list->size = 0; + list->destroy = destroy; + list->head = NULL; + list->tail = NULL; +} + +void ll_destroy(struct List* list) { + void* data; + while (list->size > 0) { + if (ll_remove(list, list->tail, (void**)&data) == 0 && list->destroy != NULL) { + list->destroy(data); + } + } + memset(list, 0, sizeof(struct List)); +} + +int ll_ins_next(struct List* list, struct ListNode* node, const void* data) { + struct ListNode* new_node; + if (node == NULL && list->size != 0) { + return -1; + } + if ((new_node = malloc(sizeof(struct ListNode))) == NULL) { + return -1; + } + + new_node->data = (void*)data; + if (list->size == 0) { + list->head = new_node; + list->head->prev = NULL; + list->head->next = NULL; + list->tail = new_node; + } else { + new_node->next = node->next; + new_node->prev = node; + if (node->next == NULL) { + list->tail = new_node; + } else { + node->next->prev = new_node; + } + node->next = new_node; + } + + list->size++; + return 0; +} + +int ll_ins_prev(struct List* list, struct ListNode* node, const void* data) { + struct ListNode* new_node; + if (node == NULL && list->size != 0) { + return -1; + } + if ((new_node = malloc(sizeof(struct ListNode))) == NULL) { + return -1; + } + + new_node->data = (void*)data; + if (list->size == 0) { + list->head = new_node; + list->head->prev = NULL; + list->head->next = NULL; + list->tail = new_node; + } else { + new_node->next = node; + new_node->prev = node->prev; + if (node->prev == NULL) { + list->head = new_node; + } else { + node->prev->next = new_node; + } + node->prev = new_node; + } + + list->size++; + return 0; +} + +int ll_remove(struct List* list, struct ListNode* node, void** data) { + if (node == NULL || list->size == 0) { + return -1; + } + + *data = node->data; + if (node == list->head) { + list->head = node->next; + if (list->head == NULL) { + list->tail = NULL; + } else { + node->next->prev = NULL; + } + } else { + node->prev->next = node->next; + if (node->next == NULL) { + list->tail = node->prev; + } else { + node->next->prev = node->prev; + } + } + free(node); + list->size--; + return 0; +} + +int ll_remove_next(struct List* list, struct ListNode* node, void** data) { + if (node->next == NULL) { + return -1; + } + return ll_remove(list, node->next, data); +} + +int ll_remove_prev(struct List* list, struct ListNode* node, void** data) { + if (node->prev == NULL) { + return -1; + } + return ll_remove(list, node->prev, data); +} + diff --git a/src/set.c b/src/set.c new file mode 100644 index 0000000..9a3eba3 --- /dev/null +++ b/src/set.c @@ -0,0 +1,124 @@ +#include "set.h" + +void set_init(struct Set* set, int (*match)(const void* a, const void* b), + void (*destroy)(void* data)) { + ll_init(set, destroy); + set->match = match; +} + +void set_destroy(struct Set* set) { + ll_destroy(set); +} + +int set_insert(struct Set* set, const void* data) { + if (set_is_member(set, data)) { + return 1; + } + return ll_ins_next(set, set->tail, data); +} + +int set_remove(struct Set* set, void** data) { + struct ListNode* node = NULL; + + for (node = set->head; node != NULL; node = node->next) { + if (set->match(*data, node->data)) { + break; + } + } + + if (node == NULL) { + return -1; + } + return ll_remove_next(set, node, data); +} + +int set_union(struct Set* setu, const struct Set* a, const struct Set* b) { + struct ListNode* node; + void* data; + + set_init(setu, a->match, NULL); + for (node = a->head; node != NULL; node = node->next) { + data = node->data; + if (ll_ins_next(setu, setu->tail, data) != 0) { + set_destroy(setu); + return -1; + } + } + + for (node = b->head; node != NULL; node = node->next) { + if (set_is_member(a, node->data)) { + continue; + } + data = node->data; + if (ll_ins_next(setu, setu->tail, data) != 0) { + set_destroy(setu); + return -1; + } + } + + return 0; +} + +int set_intersection(struct Set* seti, const struct Set* a, const struct Set* b) { + struct ListNode* node; + void* data; + + set_init(seti, a->match, NULL); + for (node = a->head; node != NULL; node = node->next) { + data = node->data; + if (set_is_member(b, data)) { + if (ll_ins_next(seti, seti->tail, data)) { + set_destroy(seti); + return -1; + } + } + } + + return 0; +} + +int set_difference(struct Set* setd, const struct Set* a, const struct Set* b) { + struct ListNode* node; + void* data; + + set_init(setd, a->match, NULL); + for (node = a->head; node != NULL; node = node->next) { + data = node->data; + if (!set_is_member(b, data)) { + if (ll_ins_next(setd, setd->tail, data)) { + set_destroy(setd); + return -1; + } + } + } + + return 0; +} + +int set_is_member(const struct Set* set, const void* data) { + for (struct ListNode* node = set->head; node != NULL; node = node->next) { + if (set->match(data, node->data)) { + return 1; + } + } + return 0; +} + +int set_is_subset(const struct Set* a, const struct Set* b) { + if (a->size > b->size) { + return 0; + } + for (struct ListNode* node = a->head; node != NULL; node = node->next) { + if (!set_is_member(b, node->data)) { + return 0; + } + } + return 1; +} + +int set_is_equal(const struct Set* a, const struct Set* b) { + if (a->size == b->size) { + return 0; + } + return set_is_subset(a, b); +} diff --git a/src/stack.c b/src/stack.c new file mode 100644 index 0000000..92d3929 --- /dev/null +++ b/src/stack.c @@ -0,0 +1,25 @@ +#include "stack.h" + +void stack_init(struct Stack* stack, void (*destroy)(void* data)) { + ll_init(stack, destroy); +} + +void stack_destroy(struct Stack* stack) { + ll_destroy(stack); +} + +int stack_push(struct Stack* stack, void *data) { + if (stack->size == 0) { + return ll_ins_next(stack, NULL, data); + } else { + return ll_ins_next(stack, stack->tail, data); + } +} + +void *stack_peek(struct Stack *stack) { + return stack->tail == NULL ? NULL : stack->tail->data; +} + +int stack_pop(struct Stack *stack, void **data) { + return ll_remove(stack, stack->tail, data); +} diff --git a/tests/tests.c b/tests/tests.c new file mode 100644 index 0000000..e90322e --- /dev/null +++ b/tests/tests.c @@ -0,0 +1,155 @@ +#include +#include + +#include "linkedlist.h" +#include "set.h" +#include "stack.h" +#include "binarytree.h" + +void print_ll(struct List* list) { + for (struct ListNode* node = list->head; node != NULL; node = node->next) { + printf(" %d", *((int*)node->data)); + } + printf("\n"); +} + +void test_ll() { + printf("\n--- LIST TEST ---\n"); + struct List* list = malloc(sizeof(struct List)); + ll_init(list, NULL); + + int i = 1; + int j = 2; + int k = 4; + + ll_ins_next(list, list->head, (void*)&i); + ll_ins_next(list, list->tail, (void*)&j); + ll_ins_next(list, list->tail, (void*)&k); + + printf("struct List: "); + print_ll(list); + + void* data; + ll_remove_next(list, list->head, &data); + + printf("struct List: "); + print_ll(list); + printf("Removed: %d\n", *((int*)data)); + + ll_destroy(list); + free(list); +} + +int int_match(const void* a, const void* b) { + return *((int*)a) == *((int*)b); +} + +void test_set() { + printf("\n--- SET TEST ---\n"); + struct Set* set = malloc(sizeof(struct Set)); + set_init(set, int_match, NULL); + + int i = 1; + int j = 2; + int k = 2; + + set_insert(set, (void*)&i); + set_insert(set, (void*)&j); + set_insert(set, (void*)&k); + + int i2 = 1; + int j2 = 4; + + struct Set* set2 = malloc(sizeof(struct Set)); + set_init(set2, int_match, NULL); + + set_insert(set2, (void*)&i2); + set_insert(set2, (void*)&j2); + + printf("struct Set 1:"); + print_ll(set); + + printf("struct Set 2:"); + print_ll(set2); + printf("\n"); + + struct Set* set_u = malloc(sizeof(struct Set)); + struct Set* set_i = malloc(sizeof(struct Set)); + struct Set* set_d = malloc(sizeof(struct Set)); + + set_union(set_u, set, set2); + printf("Union:"); + print_ll(set_u); + + set_difference(set_d, set, set2); + printf("Difference:"); + print_ll(set_d); + + set_intersection(set_i, set, set2); + printf("Intersection:"); + print_ll(set_i); + + set_destroy(set); + set_destroy(set2); + set_destroy(set_u); + set_destroy(set_i); + set_destroy(set_d); + free(set); + free(set2); + free(set_u); + free(set_i); + free(set_d); +} + +void test_stack() { + printf("\n--- STACK TEST ---\n"); + struct Stack *stack = malloc(sizeof(struct Stack)); + stack_init(stack, NULL); + + int a = 1, b = 2; + stack_push(stack, &a); + stack_push(stack, &b); + printf("struct Stack size: %lu\n", stack->size); + + int *p = NULL; + stack_pop(stack, (void **)&p); + printf("b = %d\n", *p); + + stack_pop(stack, (void **)&p); + printf("a = %d\n", *p); + printf("struct Stack size: %lu\n", stack->size); + + stack_destroy(stack); +} + +void test_bintree() { + printf("\n--- BINARY TREE TEST ---\n"); + struct BinTree *tree = malloc(sizeof(struct BinTree)); + bintree_init(tree, NULL); + + int root = 0; + int l1 = 1; + int l2 = 2; + int r1 = 12; + int r2 = 200; + + bintree_ins_left(tree, NULL, &root); + bintree_ins_left(tree, tree->root, &l1); + bintree_ins_left(tree, tree->root->left, &l2); + bintree_ins_right(tree, tree->root->left, &r2); + bintree_ins_right(tree, tree->root, &r1); + bintree_ins_right(tree, tree->root->right, &r2); + bintree_ins_left(tree, tree->root->right, &l1); + + bintree_debug_print(tree); + + bintree_destroy(tree); +} + +int main() { + test_ll(); + test_set(); + test_stack(); + test_bintree(); + return 0; +} \ No newline at end of file