From 9d41838fbdb4d22d0be6f0022c9678fd3c3b7e9e Mon Sep 17 00:00:00 2001 From: Tekin Ozbek Date: Mon, 18 May 2015 18:14:45 -0400 Subject: [PATCH 1/2] BinarySearchTree work in progress --- c/Makefile | 2 +- c/include/binarysearchtree.h | 30 +++++++++ c/src/binarysearchtree.c | 122 +++++++++++++++++++++++++++++++++++ c/src/chainedhashtable.c | 1 - 4 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 c/include/binarysearchtree.h create mode 100644 c/src/binarysearchtree.c diff --git a/c/Makefile b/c/Makefile index 8ffaa07f..0d7d4b90 100644 --- a/c/Makefile +++ b/c/Makefile @@ -45,7 +45,7 @@ INSDIR = /usr/lib OBJ = arraystack.o arrayqueue.o arraydeque.o dualarraydeque.o \ rootisharraystack.o sllist.o dllist.o selist.o skiplistsset.o skiplist.o \ - chainedhashtable.o + chainedhashtable.o binarysearchtree.o lib: $(OBJ) $(SHARED_LIB) diff --git a/c/include/binarysearchtree.h b/c/include/binarysearchtree.h new file mode 100644 index 00000000..1bce243e --- /dev/null +++ b/c/include/binarysearchtree.h @@ -0,0 +1,30 @@ +/******************************************************************************* + * File : binarysearchtree.h + * Author(s) : Tekin Ozbek + ******************************************************************************/ + +#ifndef ODS_BINARYSEARCHTREE_H_ +#define ODS_BINARYSEARCHTREE_H_ + +typedef struct btnode_t { + + void* data; + + struct btnode_t* parent; + struct btnode_t* left; + struct btnode_t* right; + +} btnode_t; + +typedef struct { + + btnode_t* root; + + size_t elem_size; + size_t length; + + int (*cmp)(void *, void *); + +} binarysearchtree_t; + +#endif diff --git a/c/src/binarysearchtree.c b/c/src/binarysearchtree.c new file mode 100644 index 00000000..b00aa51f --- /dev/null +++ b/c/src/binarysearchtree.c @@ -0,0 +1,122 @@ +/******************************************************************************* + * File : binarysearchtree.c + * Author(s) : Tekin Ozbek + ******************************************************************************/ + +#include +#include +#include + +#include + +static btnode_t* find_node(binarysearchtree_t* tree, void* data) { + + btnode_t* curr_node = tree->root; + btnode_t* prev_node = NULL; + int cmp_result; + + while (curr_node != NULL) { + + prev_node = curr_node; + + cmp_result = tree->cmp(data, curr_node->data); + + if (cmp_result < 0) + curr_node = curr_node->left; + else if (cmp_result > 0) + curr_node = curr_node->right; + else + return curr_node; + } + + return prev_node; +} + +static btnode_t* make_node(binarysearchtree_t* tree, btnode_t* p, btnode_t* l, + btnode_t* r, void* data) { + + btnode_t* new_node = malloc(sizeof(btnode_t)); + assert((void *)new_node != NULL); + + new_node->parent = p; + new_node->left = l; + new_node->right = r; + new_node->data = malloc(tree->elem_size); + + assert(new_node->data != NULL); + + /* copy the data in */ + memcpy(new_node->data, data, tree->elem_size); + + return new_node; +} + +void binarysearchtree_add(binarysearchtree_t* tree, void* data) { + + btnode_t* ins_node; + int cmp_result; + + assert((void *)tree != NULL); + assert(data != NULL); + + /* find out where we place the new data */ + ins_node = find_node(tree, data); + + if (ins_node == NULL) { + + /* tree is empty, insert to root */ + tree->root = make_node(tree, NULL, NULL, NULL, data); + + } else { + + cmp_result = tree->cmp(data, ins_node->data); + + if (cmp_result < 0) + ins_node->left = make_node(tree, ins_node, NULL, NULL, data); + else if (cmp_result > 0) + ins_node->right = make_node(tree, ins_node, NULL, NULL, data); + else /* already in the tree */ + return; + + } + + ++tree->length; +} + +int binarysearchtree_find(binarysearchtree_t* tree, void* search) { + + btnode_t* node; + int cmp_result; + + assert((void *)tree != NULL); + assert(search != NULL); + + node = tree->root; + + while (node != NULL) { + + cmp_result = tree->cmp(search, node->data); + + if (cmp_result < 0) + node = node->left; + else if (cmp_result > 0) + node = node->right; + else + return 1; + } + + return 0; +} + +void binarysearchtree_init(binarysearchtree_t* tree, size_t elem_size, + int (*comparator)(void *, void *)) { + + assert((void *)tree != NULL); + assert(comparator != NULL); + assert(elem_size > 0); + + tree->elem_size = elem_size; + tree->length = 0; + tree->cmp = comparator; + tree->root = NULL; +} diff --git a/c/src/chainedhashtable.c b/c/src/chainedhashtable.c index b65497d0..f99d6256 100644 --- a/c/src/chainedhashtable.c +++ b/c/src/chainedhashtable.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include From 15e380a799336df87de775fa917346d9f416de0f Mon Sep 17 00:00:00 2001 From: Tekin Ozbek Date: Sun, 23 Aug 2015 16:37:47 -0400 Subject: [PATCH 2/2] Binary search tree complete --- c/README.md | 259 ++++++++++++++++++----------------- c/include/binarysearchtree.h | 80 +++++++++++ c/src/binarysearchtree.c | 98 ++++++++++++- 3 files changed, 301 insertions(+), 136 deletions(-) diff --git a/c/README.md b/c/README.md index fe650dd4..b026ebbc 100644 --- a/c/README.md +++ b/c/README.md @@ -1,129 +1,130 @@ -## Open Data Structures in C - -This is an implementation of [Open Data Structures](http://opendatastructures.org) -in C. It is written in ANSI C (C89) to maximize compatibility with other -compilers. - -#### Implemented data structures - -More information on the data structures (implementation details, running times, -etc.) can be found in [the book](http://opendatastructures.org). - -* [ArrayStack](include/arraystack.h) (equivalent to FastArrayStack in the book) -* [ArrayQueue](include/arrayqueue.h) -* [ArrayDeque](include/arraydeque.h) -* [DualArrayDeque](include/dualarraydeque.h) -* [RootishArrayStack](include/rootisharraystack.h) -* [SLList](include/sllist.h) -* [DLList](include/dllist.h) -* [SEList](include/selist.h) -* [SkiplistSSet](include/skiplistsset.h) -* [SkiplistList](include/skiplist.h) -* [ChainedHashTable](include/chainedhashtable.h) - -#### How to use the library - -If you have [gcc](https://gcc.gnu.org/onlinedocs/gcc/) installed, simply run -either `make` to compile the shared object file or `make install` to compile and -install the library (by default, it is moved to `/usr/lib/libodsc.so`). -After that, you can append `-lodsc` to your compiler arguments to link your code -with the library. - -If you don't have gcc, you can modify the Makefile for your compiler (with -[clang](http://clang.llvm.org), you only need to change the compiler variable, -everything else should work the same). Or, compile the sources in `src/` with -the headers in `include/`. - -The [include](include/) directory contains the headers you will need to include -in your program. Detailed information on the functions and their arguments can -be found in the header files. - -This library follows a general structure: `[data structure]_[function]`. For -example, the function to initialize an ArrayStack is `arraystack_init`. - -##### Example - -```c -#include -#include - -int main() { - - int i; - - arraystack_t stack; - - /* initialize the struct with the size of the elements you want to store - * inside. this will allocate memory for the backing array. */ - arraystack_init(&stack, sizeof(int)); - - for (i = 0; i < 10; i++) - arraystack_push(&stack, &i); - - while (stack.length > 0) { - - arraystack_pop(&stack, &i); - printf("popped: %d\n", i); - } - - /* make sure to call dispose when you're done, to avoid memory leaks */ - arraystack_dispose(&stack); - - return 0; -} -``` - -#### Uniform iteration - -Different data structures can require different methods to efficiently iterate -over them. For example, it is possible to iterate through an ArrayStack using -`_get()` but using the same method on a DLList would be costly. Uniform -iterators provide a simple way of iterating over these data structures. Best to -consider them invalidated if you do any kind of insertion/removal on the data -structure you are iterating on. Iterators come with overhead since they have to -maintain state and keep function pointers. - -If an iterator is implemented for a data structure, it can be initialized -through `_iterator()`. Iterators have three functions: - -* `next(iterator_t *)`: Advances to the next element and returns 1, if -available. Otherwise, returns 0. If iterating in reverse, this will advance to -the previous element (**not all data structures can be iterated in reverse -order**, check the documentation for `_iterator()`). -* `elem(iterator_t *)`: Returns a pointer to the element *in* the data structure -(i.e. not a copy). Be careful not to exceed the bounds of this pointer (which is -`elem_size` bytes). -* `dispose(iterator_t *)`: Releases allocated memory. - -##### Example - -```c -#include -#include -#include - -int main() { - - int i; - - arraystack_t stack; - arraystack_init(&stack, sizeof(int)); - - for (i = 0; i < 10; i++) - arraystack_push(&stack, &i); - - /* make an iterator for stack[1,4] */ - iterator_t it; - arraystack_iterator(&stack, &it, 1, 4); - - while (it.next(&it)) - printf("%d\n", *(int *)it.elem(&it)); - - /* iterators allocate memory for state, which must be released. */ - it.dispose(&it); - - arraystack_dispose(&stack); - - return 0; -} -``` +## Open Data Structures in C + +This is an implementation of [Open Data Structures](http://opendatastructures.org) +in C. It is written in ANSI C (C89) to maximize compatibility with other +compilers. + +#### Implemented data structures + +More information on the data structures (implementation details, running times, +etc.) can be found in [the book](http://opendatastructures.org). + +* [ArrayStack](include/arraystack.h) (equivalent to FastArrayStack in the book) +* [ArrayQueue](include/arrayqueue.h) +* [ArrayDeque](include/arraydeque.h) +* [DualArrayDeque](include/dualarraydeque.h) +* [RootishArrayStack](include/rootisharraystack.h) +* [SLList](include/sllist.h) +* [DLList](include/dllist.h) +* [SEList](include/selist.h) +* [SkiplistSSet](include/skiplistsset.h) +* [SkiplistList](include/skiplist.h) +* [ChainedHashTable](include/chainedhashtable.h) +* [BinarySearchTree](include/binarysearchtree.h) + +#### How to use the library + +If you have [gcc](https://gcc.gnu.org/onlinedocs/gcc/) installed, simply run +either `make` to compile the shared object file or `make install` to compile and +install the library (by default, it is moved to `/usr/lib/libodsc.so`). +After that, you can append `-lodsc` to your compiler arguments to link your code +with the library. + +If you don't have gcc, you can modify the Makefile for your compiler (with +[clang](http://clang.llvm.org), you only need to change the compiler variable, +everything else should work the same). Or, compile the sources in `src/` with +the headers in `include/`. + +The [include](include/) directory contains the headers you will need to include +in your program. Detailed information on the functions and their arguments can +be found in the header files. + +This library follows a general structure: `[data structure]_[function]`. For +example, the function to initialize an ArrayStack is `arraystack_init`. + +##### Example + +```c +#include +#include + +int main() { + + int i; + + arraystack_t stack; + + /* initialize the struct with the size of the elements you want to store + * inside. this will allocate memory for the backing array. */ + arraystack_init(&stack, sizeof(int)); + + for (i = 0; i < 10; i++) + arraystack_push(&stack, &i); + + while (stack.length > 0) { + + arraystack_pop(&stack, &i); + printf("popped: %d\n", i); + } + + /* make sure to call dispose when you're done, to avoid memory leaks */ + arraystack_dispose(&stack); + + return 0; +} +``` + +#### Uniform iteration + +Different data structures can require different methods to efficiently iterate +over them. For example, it is possible to iterate through an ArrayStack using +`_get()` but using the same method on a DLList would be costly. Uniform +iterators provide a simple way of iterating over these data structures. Best to +consider them invalidated if you do any kind of insertion/removal on the data +structure you are iterating on. Iterators come with overhead since they have to +maintain state and keep function pointers. + +If an iterator is implemented for a data structure, it can be initialized +through `_iterator()`. Iterators have three functions: + +* `next(iterator_t *)`: Advances to the next element and returns 1, if +available. Otherwise, returns 0. If iterating in reverse, this will advance to +the previous element (**not all data structures can be iterated in reverse +order**, check the documentation for `_iterator()`). +* `elem(iterator_t *)`: Returns a pointer to the element *in* the data structure +(i.e. not a copy). Be careful not to exceed the bounds of this pointer (which is +`elem_size` bytes). +* `dispose(iterator_t *)`: Releases allocated memory. + +##### Example + +```c +#include +#include +#include + +int main() { + + int i; + + arraystack_t stack; + arraystack_init(&stack, sizeof(int)); + + for (i = 0; i < 10; i++) + arraystack_push(&stack, &i); + + /* make an iterator for stack[1,4] */ + iterator_t it; + arraystack_iterator(&stack, &it, 1, 4); + + while (it.next(&it)) + printf("%d\n", *(int *)it.elem(&it)); + + /* iterators allocate memory for state, which must be released. */ + it.dispose(&it); + + arraystack_dispose(&stack); + + return 0; +} +``` diff --git a/c/include/binarysearchtree.h b/c/include/binarysearchtree.h index 1bce243e..d4f30dc1 100644 --- a/c/include/binarysearchtree.h +++ b/c/include/binarysearchtree.h @@ -6,6 +6,8 @@ #ifndef ODS_BINARYSEARCHTREE_H_ #define ODS_BINARYSEARCHTREE_H_ +#include + typedef struct btnode_t { void* data; @@ -27,4 +29,82 @@ typedef struct { } binarysearchtree_t; +/* FUNCTION + * binarysearchtree_add + * + * DESCRIPTION + * Adds an element to the tree. + * + * PARAMETERS + * tree A valid pointer to an initialized binarysearchtree_t struct. + * elem The element that will be copied into the tree. + */ +extern void binarysearchtree_add(binarysearchtree_t* tree, + void* elem); + +/* FUNCTION + * binarysearchtree_dispose + * + * DESCRIPTION + * Frees allocated memory. Once disposed, a binarysearchtree_t structure + * should be re-initialized before use. + * + * PARAMETERS + * tree A valid pointer to an initialized binarysearchtree_t struct. + */ +void binarysearchtree_dispose(binarysearchtree_t* tree); + +/* FUNCTION + * binarysearchtree_find + * + * DESCRIPTION + * Finds an element in the tree. + * + * PARAMETERS + * tree A valid pointer to an initialized binarysearchtree_t struct. + * search The element that is being searched. + * + * RETURN VALUES + * Returns a non-zero value if the element that was being searched is + * found in the tree, zero otherwise. + */ +extern int binarysearchtree_find(binarysearchtree_t* tree, + void* search); + +/* FUNCTION + * binarysearchtree_init + * + * DESCRIPTION + * Initializes the binarysearchtree_t struct. + * + * PARAMETERS + * tree A valid pointer to a binarysearchtree_t struct. + * elem_size Size of the type that will be inserted in the tree. + * comparator Pointer to a comparator function that takes two void* + * parameters and returns an int. The function must return + * less than zero if the first parameter comes before the + * second parameter and greater than zero if vice versa. + * The function must return zero if arguments are equal. + */ +extern void binarysearchtree_init(binarysearchtree_t* tree, + size_t elem_size, + int(*comparator)(void *, void *)); + +/* FUNCTION + * binarysearchtree_remove + * + * DESCRIPTION + * Removes an element from the tree. + * + * PARAMETERS + * tree A valid pointer to an initialized binarysearchtree_t struct. + * search The element that will be removed from the tree. + * + * RETURN VALUES + * Returns a non-zero value if the element was found and removed; returns + * zero if the element was not found. + */ +extern int binarysearchtree_remove(binarysearchtree_t* tree, + void* elem); + #endif diff --git a/c/src/binarysearchtree.c b/c/src/binarysearchtree.c index b00aa51f..533d7b92 100644 --- a/c/src/binarysearchtree.c +++ b/c/src/binarysearchtree.c @@ -51,30 +51,76 @@ static btnode_t* make_node(binarysearchtree_t* tree, btnode_t* p, btnode_t* l, return new_node; } -void binarysearchtree_add(binarysearchtree_t* tree, void* data) { +static void remove_node(binarysearchtree_t* tree, btnode_t* node) { + + btnode_t* s = NULL; + btnode_t* p = NULL; + + + if (node->left != NULL) + s = node->left; + else + s = node->right; + + if (node == tree->root) { + + tree->root = s; + p = NULL; + + } else { + + p = node->parent; + + if (p->left == node) + p->left = s; + else + p->right = s; + + } + + if (s != NULL) + s->parent = p; + + free(node->data); + free(node); +} + +static void recursive_destroy_node(btnode_t* node) { + + if (node == NULL) + return; + + recursive_destroy_node(node->left); + recursive_destroy_node(node->right); + + free(node->data); + free(node); +} + +void binarysearchtree_add(binarysearchtree_t* tree, void* elem) { btnode_t* ins_node; int cmp_result; assert((void *)tree != NULL); - assert(data != NULL); + assert(elem != NULL); /* find out where we place the new data */ - ins_node = find_node(tree, data); + ins_node = find_node(tree, elem); if (ins_node == NULL) { /* tree is empty, insert to root */ - tree->root = make_node(tree, NULL, NULL, NULL, data); + tree->root = make_node(tree, NULL, NULL, NULL, elem); } else { - cmp_result = tree->cmp(data, ins_node->data); + cmp_result = tree->cmp(elem, ins_node->data); if (cmp_result < 0) - ins_node->left = make_node(tree, ins_node, NULL, NULL, data); + ins_node->left = make_node(tree, ins_node, NULL, NULL, elem); else if (cmp_result > 0) - ins_node->right = make_node(tree, ins_node, NULL, NULL, data); + ins_node->right = make_node(tree, ins_node, NULL, NULL, elem); else /* already in the tree */ return; @@ -83,6 +129,13 @@ void binarysearchtree_add(binarysearchtree_t* tree, void* data) { ++tree->length; } +void binarysearchtree_dispose(binarysearchtree_t* tree) { + + assert((void *)tree != NULL); + + recursive_destroy_node(tree->root); +} + int binarysearchtree_find(binarysearchtree_t* tree, void* search) { btnode_t* node; @@ -120,3 +173,34 @@ void binarysearchtree_init(binarysearchtree_t* tree, size_t elem_size, tree->cmp = comparator; tree->root = NULL; } + +int binarysearchtree_remove(binarysearchtree_t* tree, void* elem) { + + btnode_t* node = NULL; + btnode_t* u = NULL; + + assert((void *)tree != NULL); + assert(elem != NULL); + + node = find_node(tree, elem); + + if (node == NULL || tree->cmp(elem, node->data) != NULL) + return 0; + + if (node->left == NULL || node->right == NULL) { + + remove_node(tree, node); + + } else { + + u = node->right; + while (u->left != NULL) + u = u->left; + + memcpy(node->data, u->data, tree->elem_size); + + remove_node(tree, u); + } + + --tree->length; +}