From 19a07f806562fdc5132dcb7be354b73529c72c35 Mon Sep 17 00:00:00 2001 From: Razvan Madalin MATEI Date: Thu, 12 Mar 2015 19:53:56 +0200 Subject: [PATCH] add libds --- libds/.gitignore | 4 + libds/LICENSE | 18 +++ libds/Makefile | 29 ++++ libds/README | 33 +++++ libds/ds.h | 326 ++++++++++++++++++++++++++++++++++++++++++++ libds/hashmap.c | 154 +++++++++++++++++++++ libds/hashmap.h | 55 ++++++++ libds/heap.c | 62 +++++++++ libds/heap.h | 40 ++++++ libds/heaptest.c | 51 +++++++ libds/list.c | 145 ++++++++++++++++++++ libds/list.h | 77 +++++++++++ libds/listtest.c | 49 +++++++ libds/maptest.c | 29 ++++ libds/strutils.c | 166 ++++++++++++++++++++++ libds/strutils.h | 51 +++++++ libds/strutiltest.c | 38 ++++++ libds/tree.c | 320 +++++++++++++++++++++++++++++++++++++++++++ libds/tree.h | 54 ++++++++ libds/treetest.c | 70 ++++++++++ libds/vectest.c | 34 +++++ libds/vector.c | 122 +++++++++++++++++ libds/vector.h | 50 +++++++ 23 files changed, 1977 insertions(+) create mode 100644 libds/.gitignore create mode 100644 libds/LICENSE create mode 100644 libds/Makefile create mode 100644 libds/README create mode 100644 libds/ds.h create mode 100644 libds/hashmap.c create mode 100644 libds/hashmap.h create mode 100644 libds/heap.c create mode 100644 libds/heap.h create mode 100644 libds/heaptest.c create mode 100644 libds/list.c create mode 100644 libds/list.h create mode 100644 libds/listtest.c create mode 100644 libds/maptest.c create mode 100644 libds/strutils.c create mode 100644 libds/strutils.h create mode 100644 libds/strutiltest.c create mode 100644 libds/tree.c create mode 100644 libds/tree.h create mode 100644 libds/treetest.c create mode 100644 libds/vectest.c create mode 100644 libds/vector.c create mode 100644 libds/vector.h diff --git a/libds/.gitignore b/libds/.gitignore new file mode 100644 index 0000000..ee83e30 --- /dev/null +++ b/libds/.gitignore @@ -0,0 +1,4 @@ +*test +*.o +libds.a +*.swp diff --git a/libds/LICENSE b/libds/LICENSE new file mode 100644 index 0000000..4b5f876 --- /dev/null +++ b/libds/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2011 Zhehao Mao + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libds/Makefile b/libds/Makefile new file mode 100644 index 0000000..a934911 --- /dev/null +++ b/libds/Makefile @@ -0,0 +1,29 @@ +CFLAGS=-O2 -Wall +LDFLAGS=-L. -lds +HEADERS=list.h vector.h hashmap.h strutils.h heap.h tree.h +OBJS=list.o vector.o hashmap.o strutils.o heap.o tree.o +PREFIX=/usr/local +CC=gcc + +libds.a: $(OBJS) + ar rcs libds.a $(OBJS) + +test: listtest vectest maptest strutiltest heaptest treetest + +ds.h: $(HEADERS) + cat $(HEADERS) | sed -e 's/#include "vector.h"//' > ds.h + +%test: %test.c libds.a + $(CC) $(CFLAGS) $< $(LDFLAGS) -o $@ + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +clean: + rm -f *test *.o *.a + +install: ds.h libds.a + mkdir -p $(PREFIX)/lib + cp libds.a $(PREFIX)/lib + mkdir -p $(PREFIX)/include + cp ds.h $(PREFIX)/include diff --git a/libds/README b/libds/README new file mode 100644 index 0000000..20a1615 --- /dev/null +++ b/libds/README @@ -0,0 +1,33 @@ +libds - Simple, Memory-Safe Data Structures in C +======================================================================== + +This is a collection of C implementations of common data structures that +I use in many of my C projects. It includes the following procedures and +data structures. + +Hashmap +Vector (auto-expanding array) +Linked List +String Buffer (auto-expanding, length-recording string) + +Installation Instructions: + +Running make with no arguments will generate a shared library named libds.a. +You can then copy that library, as well as all header files, into your +project directory. If you do not wish to use separate header files, you may +generate a single header file called ds.h by running make ds.h. + +You can link your applications to the static library like so. + +gcc -static main.c -L. -lds -o main + +Assuming that main.c is your program and libds.a has been copied into the +same directory. + +Documentation on how to use the various functions and datastructures can be +found in the header files. + +License: + +libds is distributed under the MIT License, the full text of which is +reproduced in LICENSE. diff --git a/libds/ds.h b/libds/ds.h new file mode 100644 index 0000000..df7f1d3 --- /dev/null +++ b/libds/ds.h @@ -0,0 +1,326 @@ +#ifndef __LIBDS_LIST_H__ +#define __LIBDS_LIST_H__ + +/* A C implementation of a doubly-linked list. Contains void pointer values. + Can be used as a LIFO stack of FIFO queue. */ + +#define FRONT 0 +#define BACK 1 + +struct linked_node{ + void* data; + struct linked_node* next; + struct linked_node* prev; +}; + +typedef struct linked_node* lnode_p; + +struct list{ + int length; + lnode_p first; + lnode_p last; + void (*destructor)(void*); +}; + +typedef struct list * list_p; + +struct list_iter{ + lnode_p current; + char started; +}; + +typedef struct list_iter * list_iter_p; + +/* Create a linked_list object. This pointer is created on the heap and must be + cleared with a call to destroy_list to avoid memory leaks */ +list_p create_list(); + +/* Create a list_iter object for the linked_list list. The flag init can be + either FRONT or BACK and indicates whether to start the iterator from the first + or last item in the list */ +list_iter_p list_iterator(list_p list, char init); + +/* Add an item with the given value and size to the back of the list. + The data is copied by value, so the original pointer must be freed if it + was allocated on the heap. */ +void list_add(list_p list, void* data, int size); + +/* Gets the data stored in the first item of the list or NULL if the list is empty */ +void* list_first(list_p list); +/* Gets the data stored in the last item of the list or NULL if the list is empty */ +void* list_last(list_p list); + +/* Removes the last item in the list (LIFO order) and returns the data stored + there. The data returned must be freed later in order to remain memory safe. */ +void* list_pop(list_p list); +/* Removes the first item in the list (FIFO order) and returns the data stored + there. The data return must be freed later in order to remain memory safe. */ +void* list_poll(list_p list); +/* Convenience function for completely destroying an item in the list. If the end + flag is FRONT, an item will be polled from the front of the list and its data + freed. If the end flag is set to BACK, an item will be popped off the end of + the list and the data freed. */ +void list_remove(list_p list, char end); + +/* Completely free the data associated with the list. */ +void destroy_list(list_p list); + +/* Return the data held by the current item pointed to by the iterator */ +void* list_current(list_iter_p list); +/* Advances the iterator to the next item in the list and returns the data + stored there. */ +void* list_next(list_iter_p list); +/* Advances the iterator to the previous item in the list and returns the data + stored there. */ +void* list_prev(list_iter_p list); + +#endif +#ifndef __LIBDS_VECTOR_H__ +#define __LIBDS_VECTOR_H__ + +/* A C implementation of a vector, or dynamically expanding array. */ + +#include + +#define BASE_CAP 10 +#define EXPAND_RATIO 1.5 + +struct vector{ + void** data; + int * sizes; + size_t length; + size_t capacity; + void (*destructor)(void*); +}; + +typedef struct vector * vector_p; + +/* Create a vector object. It must be eventually destroyed by a call to + destroy_vector to avoid memory leaks. */ +vector_p create_vector(); +/* Create a new vector that is composed of the items in the old vector with + indices in the range of [start,end) */ +vector_p subvector(vector_p vec, int start, int end); +/* Add an item to the end of the vector */ +void vector_add(vector_p vec, void* data, size_t n); +/* Get the item at index i of the vector */ +void* vector_get(vector_p vec, size_t i); +/* Set the item at index i of the vector to the data provided. */ +int vector_set(vector_p vec, size_t i, void* data, size_t n); +/* Insert the data at index i of the vector and shift the other + items to the right. */ +int vector_insert(vector_p vec, size_t i, void* data, size_t n); +/* Get the index of the item in the vector that is equal to the data. + Equality is defined as having the same bytes in memory. */ +int vector_index(vector_p vec, void* data, size_t n); +/* Remove the item at index i of the vector and free its memory */ +void vector_remove(vector_p vec, size_t i); +/* Check to make sure there is still room in the vector and expand it if + necessary. This function is not meant to be called directly. */ +void check_length(vector_p vec); +/* Destroy the vector and free all the memory associated with it. */ +void destroy_vector(vector_p vec); +/* Swaps the pointers at indices i and j in the vector */ +void vector_swap(vector_p vec, int i, int j); + + +#endif +#ifndef __LIBDS_HASHMAP_H__ +#define __LIBDS_HASHMAP_H__ + +/* A C implementation of a Hash Map. + Uses string keys but has void pointer values */ + +#include + +#include + +#define NUM_BUCKETS 3848921 + +struct item{ + char* key; + void* val; + time_t expiry; + struct item * next; +}; + +typedef struct item item_t; + +struct hashmap{ + item_t** buckets; + size_t size; + vector_p keys; + void (*destructor)(void*); +}; + +typedef struct hashmap * hashmap_p; + +/* Create a new hashmap. The hashmap created by this method must be eventually + destroyed by a call to destroy_hashmap() to avoid memory leak */ +hashmap_p create_hashmap(); + +/* Place an entry with the value val and length len into the hashmap m and associate + it with the key key. The key and value are copied by value, not by pointer, + so if they were created on the heap, they must be freed later. */ +void hashmap_put(hashmap_p m, char* key, void* val, size_t len); + +/* Get the value of the entry in hashmap m associated with key key */ +void* hashmap_get(hashmap_p m, char* key); + +/* Remove the item associated with the key key in the hashmap m. The memory for the + entry is completely freed, so use hashmap_get and make a deep copy if you wish to + retain it. */ +void hashmap_remove(hashmap_p m, char* key); + +/* Hash function for the key key. This function is not meant to be called directly */ +size_t hash_func(char * key); + +/* Free all of the memory associated with hashmap m */ +void destroy_hashmap(hashmap_p m); + +#endif +#ifndef __LIBDS_STRUTILS_H__ +#define __LIBDS_STRUTILS_H__ + +#include + +typedef struct { + char * str; + int length; + int capacity; +} stringbuf; + +/* makes a string buffer with the given initial capacity */ +stringbuf * make_buffer(int capacity); +/* concatenate the string str into the string buffer, expanding the buffer + if necessary */ +void buffer_concat(stringbuf * buf, char * str); +/* concatenate n characters of string str in the buffer, expanding the buffer + if necessary */ +void buffer_nconcat(stringbuf * buf, char * str, int n); +/* writes the characters in str into the buffer, + expanding the buffer if necessary */ +void buffer_write(stringbuf * buf, char * str); +/* writes n characters from str into the buffer, expanding the buffer if + necessary */ +void buffer_nwrite(stringbuf * buf, char * str, int n); +/* reallocate the buffer's internal string if the length of the string exceeds + its capacity */ +void realloc_if_needed(stringbuf * buf); +/* free the buffer and its internal string */ +void destroy_buffer(stringbuf * buf); +/* safely read the entire contents of the file into a properly sized string */ +char * saferead(FILE * f); +/* join an array of strings of length len with separator sep */ +char* str_join(char **args, char * sep, int len); +/* split the string into a vector around the delimiter string */ +char ** str_split(char * str, char * delim, int * size); +/* free the elements of a string array, as well as the array itself */ +void free_str_array(char ** arr, int len); +/* strip trailing whitespace and newline characters from a string */ +void str_strip(char * str, int len); +/* convert the characters in a string to lowercase */ +void str_lower(char * str); +/* convert the characters in the string to uppercase */ +void str_upper(char * str); +/* tests whether stra is starts with the string strb */ +int str_startswith(char * stra, char * strb); +/* tests whether stra ends with the string strb */ +int str_endswith(char * stra, char * strb); +#endif /* __STRUTILS_H__ */ + + +#ifndef __LIBDS_HEAP_H__ +#define __LIBDS_HEAP_H__ + + + +#define PARENT(i) (i-1)/2 +#define LEFT(i) 2*i+1 +#define RIGHT(i) 2*i+2 + +/* heapcmpfunc is the template for the comparison function used by all heap + functions. It takes as arguments the heap itself and two integers i and j + which represent indices of two items in the heap. If the value at i is + "greater" than the value at j, this function should return an integer > 0. + If the value at i is "less" than the value at j, the function should return + an integer < 0. If the values at i and j are equal, this function should + return 0 */ +typedef int (*heapcmpfunc)(vector_p, int, int); + +struct heap { + vector_p vec; + heapcmpfunc cmpfunc; +}; + +typedef struct heap * heap_p; + +heap_p create_heap(heapcmpfunc cmpfunc); +void destroy_heap(heap_p hp); + +/* maintain the heap property starting at index i */ +void heapify(heap_p hp, int i); +/* build the heap */ +void build_heap(heap_p hp); +/* removes the first element from the heap and then adjusts to maintain the + heap property */ +void heap_remove(heap_p hp); +/* inserts the value into the heap such that the heap property is maintained */ +void heap_insert(heap_p hp, void * val, int size); + +#endif /* __HEAP_H__ */ + +#ifndef __LIBDS_TREE_H__ +#define __LIBDS_TREE_H__ + +#include + +enum { + RED, + BLACK +}; + +typedef int (*treecmpfunc)(void*,void*); + +struct tree_node { + struct tree_node * left; + struct tree_node * right; + struct tree_node * parent; + void * data; + int color; +}; + +typedef struct tree_node * tnode_p; + +tnode_p make_node(void*, int); + +struct tree { + tnode_p root; + treecmpfunc cmpfunc; +}; + +typedef struct tree * tree_p; +typedef void (*traversecb)(void*); + +tnode_p tree_insert(tree_p tr, void * data, int size); +void tree_delete(tree_p tr, tnode_p node); + +void left_rotate(tree_p tr, tnode_p node); +void right_rotate(tree_p tr, tnode_p node); + +tnode_p tree_minimum(tnode_p node); +tnode_p tree_maximum(tnode_p node); + +tnode_p tree_predecessor(tnode_p node); +tnode_p tree_successor(tnode_p node); + +tnode_p tree_search(tree_p tr, void * key); +void traverse(tnode_p node, traversecb); + +void destroy_node(tnode_p node); + +int rb_color(tnode_p node); +tnode_p rb_insert(tree_p tr, void * data, int size); +void rb_delete(tree_p tr, tnode_p node); + +#endif diff --git a/libds/hashmap.c b/libds/hashmap.c new file mode 100644 index 0000000..c2e65b7 --- /dev/null +++ b/libds/hashmap.c @@ -0,0 +1,154 @@ +#include "hashmap.h" +#include + +hashmap_p create_hashmap(){ + hashmap_p m = (hashmap_p)malloc(sizeof(struct hashmap)); + int i; + m->size=0; + m->num_buckets = DEFAULT_NUM_BUCKETS; + m->buckets = (item_t**) malloc(sizeof(item_t*) * m->num_buckets); + for(i=0; i < m->num_buckets; i++) + m->buckets[i] = NULL; + m->keys = create_vector(); + m->destructor = free; + return m; +} + +void* hashmap_get(hashmap_p m, char * key){ + if(key==NULL){ + return NULL; + } + size_t h = hash_func(key) % m->num_buckets; + item_t* itm = m->buckets[h]; + while(itm!=NULL){ + if(strcmp(key, itm->key)==0) + return itm->val; + itm = itm->next; + } + return NULL; +} + +void hashmap_put(hashmap_p m, char* key, void* val, size_t len){ + int keylen = strlen(key); + size_t h = hash_func(key) % m->num_buckets; + item_t* itm = m->buckets[h]; + item_t* last = NULL; + + while(itm!=NULL){ + if(strcmp(key, itm->key)==0){ + if(itm->val!=NULL) m->destructor(itm->val); + itm->val = malloc(len); + memcpy(itm->val, val, len); + return; + } + if(itm->next==NULL) last = itm; + itm = itm->next; + } + + itm = (item_t*)malloc(sizeof(item_t)); + itm->key = malloc(keylen+1); + memcpy(itm->key, key, keylen+1); + itm->val = malloc(len); + memcpy(itm->val, val, len); + itm->next = NULL; + if(last==NULL) m->buckets[h] = itm; + else last->next = itm; + vector_add(m->keys, itm->key, keylen+1); + m->size++; +} + +void hashmap_remove(hashmap_p m, char* key){ + int n = strlen(key); + size_t h = hash_func(key) % m->num_buckets; + item_t *itm = m->buckets[h]; + item_t *last = NULL; + int keyind; + while(itm!=NULL){ + if(strcmp(key, itm->key)==0) + break; + last = itm; + itm = itm->next; + } + + if(itm != NULL){ + if(last==NULL) + m->buckets[h] = itm->next; + else last->next = itm->next; + + free(itm->key); + m->destructor(itm->val); + free(itm); + + keyind = vector_index(m->keys, key, n); + vector_remove(m->keys, keyind); + m->size--; + } +} + +/* Uses FNV hash function, as given by Julien Walker's "The Art of Hashing" */ +size_t hash_func(char * key){ + size_t h = 2166136261; + int i; + for (i=0; key[i]!='\0'; ++i) + h = ( h * 16777619 ) ^ key[i]; + return h; +} + +void destroy_hashmap(hashmap_p m){ + int x; + item_t* itm; + for(x=0;xnum_buckets;++x){ + itm = m->buckets[x]; + while(itm!=NULL){ + free(itm->key); + m->destructor(itm->val); + free(itm); + itm = itm->next; + } + } + destroy_vector(m->keys); + free(m->buckets); + free(m); +} + +void hashmap_resize(hashmap_p m, size_t num_buckets){ + int i; + + m->buckets = (item_t **)realloc(m->buckets, + sizeof(item_t *) * num_buckets); + + for(i=0; i < m->size; i++){ + char* key = (char*) vector_get(m->keys, i); + int h = hash_func(key) % m->num_buckets; + item_t *prev = NULL; + item_t *cur = m->buckets[h]; + + while(cur != NULL){ + if(strcmp(cur->key, key)==0) + break; + prev = cur; + cur = cur->next; + } + + if(cur != NULL){ + if(prev == NULL) + m->buckets[h] = cur->next; + else prev->next = cur->next; + cur->next = NULL; + } + + h = hash_func(key) % num_buckets; + + prev = m->buckets[h]; + + if(prev == NULL) + m->buckets[h] = cur; + else { + while(prev->next != NULL) + prev = prev->next; + prev->next = cur; + } + } + + m->num_buckets = num_buckets; +} diff --git a/libds/hashmap.h b/libds/hashmap.h new file mode 100644 index 0000000..5e362dd --- /dev/null +++ b/libds/hashmap.h @@ -0,0 +1,55 @@ +#ifndef __LIBDS_HASHMAP_H__ +#define __LIBDS_HASHMAP_H__ + +/* A C implementation of a Hash Map. + Uses string keys but has void pointer values */ + +#include +#include "vector.h" + +#define DEFAULT_NUM_BUCKETS 101 + +struct item{ + char* key; + void* val; + struct item * next; +}; + +typedef struct item item_t; + +struct hashmap{ + item_t** buckets; + vector_p keys; + void (*destructor)(void*); + size_t size; + size_t num_buckets; +}; + +typedef struct hashmap * hashmap_p; + +/* Create a new hashmap. The hashmap created by this method must be eventually + destroyed by a call to destroy_hashmap() to avoid memory leak */ +hashmap_p create_hashmap(); + +/* Place an entry with the value val and length len into the hashmap m and associate + it with the key key. The key and value are copied by value, not by pointer, + so if they were created on the heap, they must be freed later. */ +void hashmap_put(hashmap_p m, char* key, void* val, size_t len); + +/* Get the value of the entry in hashmap m associated with key key */ +void* hashmap_get(hashmap_p m, char* key); + +/* Remove the item associated with the key key in the hashmap m. The memory for the + entry is completely freed, so use hashmap_get and make a deep copy if you wish to + retain it. */ +void hashmap_remove(hashmap_p m, char* key); + +/* Hash function for the key key. This function is not meant to be called directly */ +size_t hash_func(char * key); + +/* Free all of the memory associated with hashmap m */ +void destroy_hashmap(hashmap_p m); + +void hashmap_resize(hashmap_p m, size_t num_buckets); + +#endif diff --git a/libds/heap.c b/libds/heap.c new file mode 100644 index 0000000..00613be --- /dev/null +++ b/libds/heap.c @@ -0,0 +1,62 @@ +#include "heap.h" +#include +#include + +heap_p create_heap(heapcmpfunc cmpfunc){ + heap_p hp = (heap_p) malloc(sizeof(struct heap)); + hp->vec = create_vector(); + hp->cmpfunc = cmpfunc; + + return hp; +} + +void destroy_heap(heap_p hp){ + destroy_vector(hp->vec); + free(hp); +} + +void heapify(heap_p hp, int i){ + int largest; + int l = LEFT(i); + int r = RIGHT(i); + + if(l < hp->vec->length && hp->cmpfunc(hp->vec, l, i) > 0) + largest = l; + else largest = i; + + if(r < hp->vec->length && hp->cmpfunc(hp->vec, r, largest) > 0) + largest = r; + + if(largest != i){ + vector_swap(hp->vec, i, largest); + heapify(hp, largest); + } +} + +void build_heap(heap_p hp){ + int i; + + for(i=PARENT(hp->vec->length-1); i>=0; i--){ + heapify(hp, i); + } +} + +void heap_remove(heap_p hp){ + + vector_swap(hp->vec, 0, hp->vec->length-1); + vector_remove(hp->vec, hp->vec->length-1); + + heapify(hp, 0); +} + +void heap_insert(heap_p hp, void * val, int size){ + int i; + + vector_add(hp->vec, val, size); + + for(i=hp->vec->length-1; i>0; i=PARENT(i)){ + if(hp->cmpfunc(hp->vec, PARENT(i), i) > 0) + break; + vector_swap(hp->vec, PARENT(i), i); + } +} diff --git a/libds/heap.h b/libds/heap.h new file mode 100644 index 0000000..c1afcd9 --- /dev/null +++ b/libds/heap.h @@ -0,0 +1,40 @@ +#ifndef __LIBDS_HEAP_H__ +#define __LIBDS_HEAP_H__ + +#include "vector.h" + +#define PARENT(i) (i-1)/2 +#define LEFT(i) 2*i+1 +#define RIGHT(i) 2*i+2 + +/* heapcmpfunc is the template for the comparison function used by all heap + functions. It takes as arguments the heap itself and two integers i and j + which represent indices of two items in the heap. If the value at i is + "greater" than the value at j, this function should return an integer > 0. + If the value at i is "less" than the value at j, the function should return + an integer < 0. If the values at i and j are equal, this function should + return 0 */ +typedef int (*heapcmpfunc)(vector_p, int, int); + +struct heap { + vector_p vec; + heapcmpfunc cmpfunc; +}; + +typedef struct heap * heap_p; + +heap_p create_heap(heapcmpfunc cmpfunc); +void destroy_heap(heap_p hp); + +/* maintain the heap property starting at index i */ +void heapify(heap_p hp, int i); +/* build the heap */ +void build_heap(heap_p hp); +/* removes the first element from the heap and then adjusts to maintain the + heap property */ +void heap_remove(heap_p hp); +/* inserts the value into the heap such that the heap property is maintained */ +void heap_insert(heap_p hp, void * val, int size); + +#endif /* __HEAP_H__ */ + diff --git a/libds/heaptest.c b/libds/heaptest.c new file mode 100644 index 0000000..fe1a6a9 --- /dev/null +++ b/libds/heaptest.c @@ -0,0 +1,51 @@ +#include "heap.h" +#include + +int cmpfunc(vector_p heap, int i, int j){ + int * iVal; + int * jVal; + + iVal = (int*)vector_get(heap, i); + jVal = (int*)vector_get(heap, j); + + return (*iVal) - (*jVal); +} + +void print_heap(vector_p heap){ + int i; + int * iVal; + + for(i=0; ilength; i++){ + iVal = (int*)vector_get(heap, i); + printf("%d, ", *iVal); + } + + printf("\n"); +} + +int main(void){ + heap_p hp = create_heap(cmpfunc); + int i; + + for(i=0; i<8; i++){ + vector_add(hp->vec, &i, sizeof(int)); + } + + build_heap(hp); + + print_heap(hp->vec); + + for(i=8; i<10; i++){ + heap_insert(hp, &i, sizeof(int)); + } + + print_heap(hp->vec); + + heap_remove(hp); + + print_heap(hp->vec); + + destroy_heap(hp); + + return 0; +} diff --git a/libds/list.c b/libds/list.c new file mode 100644 index 0000000..242e7f1 --- /dev/null +++ b/libds/list.c @@ -0,0 +1,145 @@ +#include "list.h" +#include +#include + + +list_p create_list(){ + list_p list = (list_p) malloc(sizeof(struct list)); + list->length = 0; + list->first = NULL; + list->last = NULL; + list->destructor = free; + return list; +} + +list_iter_p list_iterator(list_p list, char init){ + list_iter_p iter = (list_iter_p)malloc(sizeof(struct list_iter)); + if(init==FRONT){ + iter->current = list->first; + } + else if(init==BACK){ + iter->current = list->last; + } + else return NULL; + iter->started = 0; + return iter; +} + +void list_add(list_p list, void* data, int size){ + lnode_p node = (lnode_p)malloc(sizeof(struct linked_node)); + node->data = malloc(size); + memcpy(node->data, data, size); + + if(list->first==NULL){ + node->prev = NULL; + node->next = NULL; + list->first = node; + list->last = node; + } + else{ + list->last->next = node; + node->prev = list->last; + node->next = NULL; + list->last = node; + } + list->length++; +} + +void* list_current(list_iter_p iter){ + if(iter->started&&iter->current!=NULL) + return iter->current->data; + return NULL; +} + +void* list_next(list_iter_p iter){ + if(!iter->started&&iter->current!=NULL){ + iter->started=1; + return iter->current->data; + } + if(iter->current!=NULL){ + iter->current = iter->current->next; + return list_current(iter); + } + return NULL; +} + +void* list_prev(list_iter_p iter){ + if(!iter->started&&iter->current!=NULL){ + iter->started=1; + return iter->current->data; + } + if(iter->current!=NULL){ + iter->current = iter->current->prev; + return list_current(iter); + } + return NULL; +} + +void* list_first(list_p list){ + return list->first->data; +} + +void* list_last(list_p list){ + return list->last->data; +} + +void* list_pop(list_p list){ + lnode_p last = list->last; + if(last == NULL) return NULL; + + if (list->first == list->last) { + list->first = NULL; + list->last = NULL; + } else { + list->last = last->prev; + last->prev->next = NULL; + } + + void* data = last->data; + free(last); + list->length--; + return data; +} + +void* list_poll(list_p list){ + lnode_p first = list->first; + + if(first == NULL) + return NULL; + + if (list->first == list->last) { + list->first = NULL; + list->last = NULL; + } else { + list->first = first->next; + first->next->prev = NULL; + } + + void* data = first->data; + free(first); + list->length--; + return data; +} + +void list_remove(list_p list, char end){ + void * data; + if(end == FRONT) + data = list_poll(list); + else if (end == BACK) + data = list_pop(list); + else return; + list->destructor(data); +} + +void destroy_list(list_p list){ + lnode_p cur = list->first; + lnode_p next; + while(cur!=NULL){ + next = cur->next; + list->destructor(cur->data); + free(cur); + cur = next; + } + free(list); +} + diff --git a/libds/list.h b/libds/list.h new file mode 100644 index 0000000..ec64e25 --- /dev/null +++ b/libds/list.h @@ -0,0 +1,77 @@ +#ifndef __LIBDS_LIST_H__ +#define __LIBDS_LIST_H__ + +/* A C implementation of a doubly-linked list. Contains void pointer values. + Can be used as a LIFO stack of FIFO queue. */ + +#define FRONT 0 +#define BACK 1 + +struct linked_node{ + void* data; + struct linked_node* next; + struct linked_node* prev; +}; + +typedef struct linked_node* lnode_p; + +struct list{ + int length; + lnode_p first; + lnode_p last; + void (*destructor)(void*); +}; + +typedef struct list * list_p; + +struct list_iter{ + lnode_p current; + char started; +}; + +typedef struct list_iter * list_iter_p; + +/* Create a linked_list object. This pointer is created on the heap and must be + cleared with a call to destroy_list to avoid memory leaks */ +list_p create_list(); + +/* Create a list_iter object for the linked_list list. The flag init can be + either FRONT or BACK and indicates whether to start the iterator from the first + or last item in the list */ +list_iter_p list_iterator(list_p list, char init); + +/* Add an item with the given value and size to the back of the list. + The data is copied by value, so the original pointer must be freed if it + was allocated on the heap. */ +void list_add(list_p list, void* data, int size); + +/* Gets the data stored in the first item of the list or NULL if the list is empty */ +void* list_first(list_p list); +/* Gets the data stored in the last item of the list or NULL if the list is empty */ +void* list_last(list_p list); + +/* Removes the last item in the list (LIFO order) and returns the data stored + there. The data returned must be freed later in order to remain memory safe. */ +void* list_pop(list_p list); +/* Removes the first item in the list (FIFO order) and returns the data stored + there. The data return must be freed later in order to remain memory safe. */ +void* list_poll(list_p list); +/* Convenience function for completely destroying an item in the list. If the end + flag is FRONT, an item will be polled from the front of the list and its data + freed. If the end flag is set to BACK, an item will be popped off the end of + the list and the data freed. */ +void list_remove(list_p list, char end); + +/* Completely free the data associated with the list. */ +void destroy_list(list_p list); + +/* Return the data held by the current item pointed to by the iterator */ +void* list_current(list_iter_p list); +/* Advances the iterator to the next item in the list and returns the data + stored there. */ +void* list_next(list_iter_p list); +/* Advances the iterator to the previous item in the list and returns the data + stored there. */ +void* list_prev(list_iter_p list); + +#endif diff --git a/libds/listtest.c b/libds/listtest.c new file mode 100644 index 0000000..2b51d31 --- /dev/null +++ b/libds/listtest.c @@ -0,0 +1,49 @@ +#include "list.h" +#include +#include +#include + +int main(int argc, char** argv){ + printf("%ld\n", sizeof(struct list)); + printf("%ld\n", sizeof(struct linked_node)); + list_p list = create_list(); + list_p list2 = create_list(); + int x; + int * pi; + + x = 0; + list_add(list, &x, sizeof(int)); + list_remove(list, FRONT); + + list_add(list, &x, sizeof(int)); + list_remove(list, BACK); + + for(x=0;x<10;x++){ + list_add(list, (void*)&x, sizeof(int)); + list_add(list2, (void*)&x, sizeof(int)); + } + + list_iter_p iter = list_iterator(list, FRONT); + + while(list_next(iter)!=NULL){ + pi = (int*)list_current(iter); + printf("%d\n", *pi); + } + + destroy_list(list); + + list_remove(list2, FRONT); + list_remove(list2, BACK); + + free(iter); + iter = list_iterator(list2, 1); + + while(list_prev(iter)!=NULL){ + pi = (int*)list_current(iter); + printf("%d\n", *pi); + } + destroy_list(list2); + free(iter); + + return 0; +} diff --git a/libds/maptest.c b/libds/maptest.c new file mode 100644 index 0000000..ac26c99 --- /dev/null +++ b/libds/maptest.c @@ -0,0 +1,29 @@ +#include "hashmap.h" +#include "vector.h" +#include +#include + +int main(void){ + hashmap_p m = create_hashmap(); + char* res; + hashmap_put(m, "key", (void*)"val", 4); + hashmap_put(m, "key", (void*)"val2", 5); + printf("hashmap size: %d\n", (int) m->size); + res = (char*)hashmap_get(m, "key"); + printf("key: %s\n", res); + hashmap_remove(m, "key"); + printf("hashmap size: %d\n", (int) m->size); + + hashmap_put(m, "key1", (void*)"val1", 5); + hashmap_put(m, "key2", (void*)"val2", 5); + hashmap_put(m, "key3", (void*)"val3", 5); + + hashmap_resize(m, 211); + + res = (char*) hashmap_get(m, "key1"); + printf("key: %s\n", res); + printf("num_buckets: %d\n", (int) m->num_buckets); + + destroy_hashmap(m); + return 0; +} diff --git a/libds/strutils.c b/libds/strutils.c new file mode 100644 index 0000000..1dcd0ee --- /dev/null +++ b/libds/strutils.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include "strutils.h" + +char * saferead(FILE * f){ + int len; + char * buf; + fseek(f, 0, SEEK_END); + len = ftell(f); + fseek(f, 0, SEEK_SET); + buf = (char*)malloc(sizeof(char)*(len+1)); + fread(buf, sizeof(char), len, f); + buf[len] = '\0'; + return buf; +} + +char * str_join(char **args, char * sep, int len){ + int i; + int size; + char * str; + int seplen = strlen(sep); + + if(len==0) return NULL; + + size = (len-1) * seplen; + for(i=0; i= cap){ + cap = len * 1.5; + array = (char**)realloc(array, sizeof(char*) * cap); + } + slen = strlen(tok); + if(slen > 0){ + array[len] = (char*)malloc(slen+1); + strncpy(array[len], tok, slen); + array[len][slen] = 0; + len++; + } + tok = strtok(NULL, delim); + } + + *size = len; + return array; +} + +void free_str_array(char ** arr, int len){ + int i; + for(i=0; ilength = 0; + buf->capacity = capacity; + buf->str = (char*)malloc(sizeof(char)*capacity); + memset(buf->str, 0, capacity); + return buf; +} + +void buffer_write(stringbuf * buf, char * str){ + int len = strlen(str); + buf->length = len; + realloc_if_needed(buf); + strcpy(buf->str, str); +} + +void buffer_nwrite(stringbuf * buf, char * str, int n){ + buf->length = n; + realloc_if_needed(buf); + strncpy(buf->str, str, n); + buf->str[n] = '\0'; +} + +void buffer_concat(stringbuf * buf, char * str){ + int len = strlen(str); + buf->length += len; + realloc_if_needed(buf); + strcat(buf->str, str); +} + +void buffer_nconcat(stringbuf * buf, char * str, int len){ + buf->length += len; + realloc_if_needed(buf); + strncat(buf->str, str, len); + buf->str[buf->length] = 0; +} + +void realloc_if_needed(stringbuf * buf){ + if(buf->capacity <= buf->length){ + buf->capacity = buf->length * 1.25; + buf->str = realloc(buf->str, buf->capacity); + } +} + +void destroy_buffer(stringbuf * buf){ + free(buf->str); + free(buf); +} + +void str_strip(char * str, int len){ + int i; + char c; + for(i=len-1; i>=0; i--){ + c = str[i]; + if(c=='\n'||c=='\r'||c=='\t'||c==' ') + str[i] = 0; + else break; + } +} + +void str_lower(char * str){ + int i; + for(i=0; str[i]; i++){ + if(isupper(str[i])){ + str[i] += 32; + } + } +} + +void str_upper(char * str){ + int i; + for(i=0; str[i]; i++){ + if(islower(str[i])){ + str[i] -= 32; + } + } +} + +int str_startswith(char * stra, char * strb){ + int len = strlen(strb); + return strncmp(stra, strb, len) == 0; +} + +int str_endswith(char * stra, char * strb){ + int lena = strlen(stra); + int lenb = strlen(strb); + + if(lenb > lena) return 0; + + return strcmp(stra+(lena-lenb), strb)==0; +} diff --git a/libds/strutils.h b/libds/strutils.h new file mode 100644 index 0000000..0e8e0fe --- /dev/null +++ b/libds/strutils.h @@ -0,0 +1,51 @@ +#ifndef __LIBDS_STRUTILS_H__ +#define __LIBDS_STRUTILS_H__ + +#include + +typedef struct { + char * str; + int length; + int capacity; +} stringbuf; + +/* makes a string buffer with the given initial capacity */ +stringbuf * make_buffer(int capacity); +/* concatenate the string str into the string buffer, expanding the buffer + if necessary */ +void buffer_concat(stringbuf * buf, char * str); +/* concatenate n characters of string str in the buffer, expanding the buffer + if necessary */ +void buffer_nconcat(stringbuf * buf, char * str, int n); +/* writes the characters in str into the buffer, + expanding the buffer if necessary */ +void buffer_write(stringbuf * buf, char * str); +/* writes n characters from str into the buffer, expanding the buffer if + necessary */ +void buffer_nwrite(stringbuf * buf, char * str, int n); +/* reallocate the buffer's internal string if the length of the string exceeds + its capacity */ +void realloc_if_needed(stringbuf * buf); +/* free the buffer and its internal string */ +void destroy_buffer(stringbuf * buf); +/* safely read the entire contents of the file into a properly sized string */ +char * saferead(FILE * f); +/* join an array of strings of length len with separator sep */ +char* str_join(char **args, char * sep, int len); +/* split the string into a vector around the delimiter string */ +char ** str_split(char * str, char * delim, int * size); +/* free the elements of a string array, as well as the array itself */ +void free_str_array(char ** arr, int len); +/* strip trailing whitespace and newline characters from a string */ +void str_strip(char * str, int len); +/* convert the characters in a string to lowercase */ +void str_lower(char * str); +/* convert the characters in the string to uppercase */ +void str_upper(char * str); +/* tests whether stra is starts with the string strb */ +int str_startswith(char * stra, char * strb); +/* tests whether stra ends with the string strb */ +int str_endswith(char * stra, char * strb); +#endif /* __STRUTILS_H__ */ + + diff --git a/libds/strutiltest.c b/libds/strutiltest.c new file mode 100644 index 0000000..782f195 --- /dev/null +++ b/libds/strutiltest.c @@ -0,0 +1,38 @@ +#include "strutils.h" +#include "vector.h" +#include + +int main(int argc, char *argv[]){ + char str[256]; + stringbuf * buf; + char * joinstr; + char ** array; + int len; + FILE * f; + int nb; + + if(argc < 2){ + printf("Usage: %s filename\n", argv[0]); + exit(1); + } + f = fopen(argv[1], "r"); + buf = make_buffer(256); + + while((nb = fread(str, sizeof(char), 255, f)) > 0){ + str[nb] = '\0'; + buffer_concat(buf, str); + } + printf("%s", buf->str); + + array = str_split(buf->str, " ", &len); + joinstr = str_join(array, " ", len); + + printf("%s", joinstr); + + free_str_array(array, len); + + free(joinstr); + destroy_buffer(buf); + fclose(f); + return 0; +} diff --git a/libds/tree.c b/libds/tree.c new file mode 100644 index 0000000..d153d76 --- /dev/null +++ b/libds/tree.c @@ -0,0 +1,320 @@ +#include "tree.h" +#include + +tnode_p make_node(void * data, int size){ + tnode_p node = (tnode_p)malloc(sizeof(struct tree_node)); + node->data = malloc(size); + memcpy(node->data, data, size); + node->parent = NULL; + node->left = NULL; + node->right = NULL; + return node; +} + +tnode_p tree_insert(tree_p tr, void * data, int size){ + tnode_p node = make_node(data, size); + tnode_p parent = NULL; + tnode_p current = tr->root; + + while(current != NULL){ + parent = current; + if(tr->cmpfunc(node->data, current->data) < 0){ + current = current->left; + } else { + current = current->right; + } + } + + node->parent = parent; + if(parent == NULL) + tr->root = node; + else if(tr->cmpfunc(node->data, parent->data) < 0) + parent->left = node; + else parent->right = node; + + return node; +} + +static tnode_p pull_out(tree_p tr, tnode_p node){ + tnode_p parent, current, next; + + if(node->left == NULL || node->right == NULL) + current = node; + else current = tree_successor(node); + + parent = current->parent; + + if(current->left != NULL) + next = current->left; + else next = current->right; + + if(next != NULL) + next->parent = parent; + + if(parent == NULL) + tr->root = next; + else if(current == parent->left) + parent->left = next; + else parent->right = next; + + free(node->data); + + if(node != current) + node->data = current->data; + + current->data = NULL; + + return current; +} + +void tree_delete(tree_p tr, tnode_p node){ + tnode_p current = pull_out(tr, node); + + current->parent = current->left = current->right = NULL; + free(current); +} + +tnode_p tree_minimum(tnode_p node){ + while(node->left != NULL) + node = node->left; + return node; +} + +tnode_p tree_maximum(tnode_p node){ + while(node->right != NULL) + node = node->right; + return node; +} + +tnode_p tree_predecessor(tnode_p node){ + tnode_p next; + + if(node->left != NULL) + return tree_maximum(node->left); + + next = node->parent; + + while(next != NULL && node == next->left){ + node = next; + next = next->parent; + } + return next; +} + +tnode_p tree_successor(tnode_p node){ + tnode_p next; + + if(node->right != NULL) + return tree_minimum(node->right); + + next = node->parent; + + while(next != NULL && node == next->right){ + node = next; + next = next->parent; + } + return next; +} + +static tnode_p search_r(tnode_p node, treecmpfunc cmpfunc, void * key){ + int res; + + if(node == NULL) return NULL; + + res = cmpfunc(key, node->data); + + if(res == 0) return node; + if(res < 0) return search_r(node->left, cmpfunc, key); + return search_r(node->right, cmpfunc, key); +} + +tnode_p tree_search(tree_p tr, void * key){ + return search_r(tr->root, tr->cmpfunc, key); +} + +void traverse(tnode_p node, traversecb tcb){ + if(node != NULL){ + tcb(node->data); + traverse(node->left, tcb); + traverse(node->right, tcb); + } +} + +void left_rotate(tree_p tr, tnode_p node){ + tnode_p right = node->right; + if(right == NULL) return; + + node->right = right->left; + if(right->left != NULL) + right->left->parent = node; + + right->parent = node->parent; + + if(node->parent == NULL) + tr->root = right; + else if(node->parent->left == node) + node->parent->left = right; + else node->parent->right = right; + + right->left = node; + node->parent = right; +} + +void right_rotate(tree_p tr, tnode_p node){ + tnode_p left = node->left; + if(left == NULL) return; + + node->left = left->right; + if(left->right != NULL) + left->right->parent = node; + + left->parent = node->parent; + + if(node->parent == NULL) + tr->root = left; + else if(node->parent->left == node) + node->parent->left = left; + else node->parent->right = left; + + left->right = node; + node->parent = left; +} + +void destroy_node(tnode_p node){ + if(node->left != NULL) destroy_node(node->left); + if(node->right != NULL) destroy_node(node->right); + + node->left = NULL; + node->right = NULL; + node->parent = NULL; + free(node->data); + node->data = NULL; + free(node); +} + +int rb_color(tnode_p node){ + if(node == NULL) return BLACK; + return node->color; +} + +tnode_p rb_insert(tree_p tr, void * data, int size){ + tnode_p node, current, uncle, parent; + + current = node = tree_insert(tr, data, size); + node->color = RED; + + while(current != tr->root && rb_color(current->parent) == RED){ + parent = current->parent; + if(parent == parent->parent->left){ + uncle = parent->parent->right; + if(rb_color(uncle) == RED){ + parent->color = BLACK; + uncle->color = BLACK; + current = parent->parent; + current->color = RED; + } else if(current == parent->right){ + current = parent; + left_rotate(tr, current); + } else { + parent->color = BLACK; + parent->parent->color = RED; + right_rotate(tr, parent->parent); + } + } else { + uncle = parent->parent->left; + if(rb_color(uncle) == RED){ + parent->color = BLACK; + uncle->color = BLACK; + current = parent->parent; + current->color = RED; + } else if(current == parent->left){ + current = parent; + right_rotate(tr, current); + } else { + parent->color = BLACK; + parent->parent->color = RED; + left_rotate(tr, parent->parent); + } + } + } + + tr->root->color = BLACK; + + return node; +} + +static void rb_delete_fixup(tree_p tr, tnode_p parent, tnode_p node){ + tnode_p sibling; + while(node != tr->root && rb_color(node) == BLACK){ + if( node == parent->left ){ + sibling = parent->right; + if(rb_color(sibling) == RED){ + sibling->color = BLACK; + parent->color = RED; + left_rotate(tr, parent); + sibling = parent->right; + } + + if(rb_color(sibling->left) == BLACK + && rb_color(sibling->right) == BLACK){ + sibling->color = RED; + node = parent; + parent = parent->parent; + } else if(rb_color(sibling->right) == BLACK){ + sibling->left->color = RED; + right_rotate(tr, sibling); + sibling = parent->right; + } else { + sibling->color = parent->color; + parent->color = BLACK; + sibling->right->color = BLACK; + left_rotate(tr, parent); + node = tr->root; + parent = NULL; + } + } + else{ + sibling = parent->left; + if(rb_color(sibling) == RED){ + sibling->color = BLACK; + parent->color = RED; + right_rotate(tr, parent); + sibling = parent->left; + } + + if(rb_color(sibling->left) == BLACK + && rb_color(sibling->right) == BLACK){ + sibling->color = RED; + node = parent; + parent = parent->parent; + } else if(rb_color(sibling->left) == BLACK){ + sibling->right->color = RED; + left_rotate(tr, sibling); + sibling = parent->left; + } else { + sibling->color = parent->color; + parent->color = BLACK; + sibling->left->color = BLACK; + right_rotate(tr, parent); + node = tr->root; + parent = NULL; + } + } + } + if(node != NULL) node->color = BLACK; +} + +void rb_delete(tree_p tr, tnode_p node){ + tnode_p current = pull_out(tr, node); + tnode_p next; + + if(current->left != NULL) + next = current->left; + else next = current->right; + + if(rb_color(current) == BLACK) + rb_delete_fixup(tr, current->parent, next); + + current->parent = current->left = current->right = NULL; + free(current); +} diff --git a/libds/tree.h b/libds/tree.h new file mode 100644 index 0000000..13e23d1 --- /dev/null +++ b/libds/tree.h @@ -0,0 +1,54 @@ +#ifndef __LIBDS_TREE_H__ +#define __LIBDS_TREE_H__ + +#include + +enum { + RED, + BLACK +}; + +typedef int (*treecmpfunc)(void*,void*); + +struct tree_node { + struct tree_node * left; + struct tree_node * right; + struct tree_node * parent; + void * data; + int color; +}; + +typedef struct tree_node * tnode_p; + +tnode_p make_node(void*, int); + +struct tree { + tnode_p root; + treecmpfunc cmpfunc; +}; + +typedef struct tree * tree_p; +typedef void (*traversecb)(void*); + +tnode_p tree_insert(tree_p tr, void * data, int size); +void tree_delete(tree_p tr, tnode_p node); + +void left_rotate(tree_p tr, tnode_p node); +void right_rotate(tree_p tr, tnode_p node); + +tnode_p tree_minimum(tnode_p node); +tnode_p tree_maximum(tnode_p node); + +tnode_p tree_predecessor(tnode_p node); +tnode_p tree_successor(tnode_p node); + +tnode_p tree_search(tree_p tr, void * key); +void traverse(tnode_p node, traversecb); + +void destroy_node(tnode_p node); + +int rb_color(tnode_p node); +tnode_p rb_insert(tree_p tr, void * data, int size); +void rb_delete(tree_p tr, tnode_p node); + +#endif diff --git a/libds/treetest.c b/libds/treetest.c new file mode 100644 index 0000000..cf20b37 --- /dev/null +++ b/libds/treetest.c @@ -0,0 +1,70 @@ +#include +#include +#include "tree.h" + +int intcmpfunc(void* a, void* b){ + int *ia, *ib; + ia = (int*) a; + ib = (int*) b; + return *ia - *ib; +} + +void print_data(void * data){ + int * pi = (int*) data; + printf("%d\n", *pi); +} + +void insert_int(tree_p tr, int x){ + rb_insert(tr, &x, sizeof(int)); +} + +void print_successor(tnode_p node){ + int *pia, *pib; + tnode_p next = tree_successor(node); + pia = (int*) node->data; + pib = (int*) next->data; + printf("The successor to %d is %d\n", *pia, *pib); +} + +void findthree(tree_p tr){ + int x = 3; + tnode_p node = tree_search(tr, &x); + if(node != NULL) + printf("We found it!\n"); +} + +int main(void){ + struct tree tr; + tr.root = NULL; + tr.cmpfunc = intcmpfunc; + + insert_int(&tr, 15); + insert_int(&tr, 5); + insert_int(&tr, 3); + insert_int(&tr, 12); + insert_int(&tr, 10); + insert_int(&tr, 6); + insert_int(&tr, 7); + insert_int(&tr, 16); + insert_int(&tr, 20); + insert_int(&tr, 18); + insert_int(&tr, 23); + + findthree(&tr); + + traverse(tr.root, print_data); + + print_successor(tr.root->left); + + rb_delete(&tr, tr.root->left); + rb_delete(&tr, tr.root->left->right); + rb_delete(&tr, tr.root->left->left); + /*left_rotate(&tr, tr.root->right); + right_rotate(&tr, tr.root->right);*/ + + traverse(tr.root, print_data); + + destroy_node(tr.root); + + return 0; +} diff --git a/libds/vectest.c b/libds/vectest.c new file mode 100644 index 0000000..1b57750 --- /dev/null +++ b/libds/vectest.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include "vector.h" + +int main(void){ + vector_p vec = create_vector(); + vector_p subvec; + int x; + char *str = "hello, world"; + char *str2 = "goodbye, world"; + for(x=0;x<15;x++){ + vector_add(vec, (void*)str, strlen(str)+1); + } + vector_insert(vec, 4, (void*) str2, strlen(str2)+1); + vector_set(vec, 7, (void*) str2, strlen(str2)+1); + vector_remove(vec, 4); + printf("%d\n", (int)vec->length); + + subvec = subvector(vec, 1, 5); + + for(x=0;xlength;x++){ + printf("%s\n", (char*)vector_get(vec, x)); + } + + printf("\n"); + + for(x=0;xlength;x++){ + printf("%s\n", (char*)vector_get(subvec, x)); + } + destroy_vector(vec); + destroy_vector(subvec); + return 0; +} diff --git a/libds/vector.c b/libds/vector.c new file mode 100644 index 0000000..d0a39e7 --- /dev/null +++ b/libds/vector.c @@ -0,0 +1,122 @@ +#include "vector.h" +#include + +vector_p create_vector(){ + vector_p vec = (vector_p)malloc(sizeof(struct vector)); + vec->data = (void**)malloc(sizeof(void*)*BASE_CAP); + vec->sizes = (int*)malloc(sizeof(int)*BASE_CAP); + vec->capacity = BASE_CAP; + vec->length = 0; + vec->destructor = free; + return vec; +} + +vector_p subvector(vector_p vec, int start, int end){ + vector_p subvec = create_vector(); + int i; + void * val; + for(i=start; idata[i]; + vector_add(subvec, val, vec->sizes[i]); + } + return subvec; +} + +void check_length(vector_p vec){ + if(vec->length >= vec->capacity){ + vec->capacity*=EXPAND_RATIO; + vec->data = (void**)realloc((void*)vec->data, + vec->capacity*sizeof(void*)); + vec->sizes = (int*)realloc((void*)vec->sizes, + vec->capacity*sizeof(int)); + } +} + +void vector_add(vector_p vec, void* data, size_t n){ + check_length(vec); + vec->data[vec->length] = malloc(n); + vec->sizes[vec->length] = n; + memcpy(vec->data[vec->length], data, n); + vec->length++; +} + +void* vector_get(vector_p vec, size_t i){ + if(i >= vec->length) + return NULL; + return vec->data[i]; +} + +int vector_set(vector_p vec, size_t i, void* data, size_t n){ + if(i >= vec->length) + return -1; + vec->destructor(vec->data[i]); + vec->data[i] = malloc(n); + vec->sizes[i] = n; + memcpy(vec->data[i], data, n); + return 0; +} + +int vector_insert(vector_p vec, size_t i, void* data, size_t n){ + int x; + + if(i > vec->length) + return -1; + + check_length(vec); + for(x=vec->length;x>=i;x--){ + vec->data[x+1] = vec->data[x]; + vec->sizes[x+1] = vec->sizes[x+1]; + } + vec->data[i] = malloc(n); + vec->sizes[i] = n; + memcpy(vec->data[i], data, n); + vec->length++; + return 0; +} + +void vector_remove(vector_p vec, size_t i){ + int x; + if(i >= vec->length) + return; + vec->destructor(vec->data[i]); + vec->length--; + for(x=i;xlength;++x){ + vec->data[x] = vec->data[x+1]; + vec->sizes[x] = vec->sizes[x+1]; + } +} + +int vector_index(vector_p vec, void* data, size_t n){ + int x; + void* check; + for(x=0;xlength;++x){ + check = vec->data[x]; + if(check==data||memcmp(check, data, n)==0){ + return x; + } + } + return -1; +} + +void destroy_vector(vector_p vec){ + int i; + for(i=0;ilength;i++){ + vec->destructor(vec->data[i]); + } + free(vec->data); + free(vec->sizes); + free(vec); +} + + +void vector_swap(vector_p vec, int i, int j){ + void * temp; + + if(i >= vec->length || j >= vec->length) + return; + + temp = vec->data[i]; + vec->data[i] = vec->data[j]; + vec->data[j] = temp; +} + diff --git a/libds/vector.h b/libds/vector.h new file mode 100644 index 0000000..afbf0a7 --- /dev/null +++ b/libds/vector.h @@ -0,0 +1,50 @@ +#ifndef __LIBDS_VECTOR_H__ +#define __LIBDS_VECTOR_H__ + +/* A C implementation of a vector, or dynamically expanding array. */ + +#include + +#define BASE_CAP 10 +#define EXPAND_RATIO 1.5 + +struct vector{ + void** data; + int * sizes; + size_t length; + size_t capacity; + void (*destructor)(void*); +}; + +typedef struct vector * vector_p; + +/* Create a vector object. It must be eventually destroyed by a call to + destroy_vector to avoid memory leaks. */ +vector_p create_vector(); +/* Create a new vector that is composed of the items in the old vector with + indices in the range of [start,end) */ +vector_p subvector(vector_p vec, int start, int end); +/* Add an item to the end of the vector */ +void vector_add(vector_p vec, void* data, size_t n); +/* Get the item at index i of the vector */ +void* vector_get(vector_p vec, size_t i); +/* Set the item at index i of the vector to the data provided. */ +int vector_set(vector_p vec, size_t i, void* data, size_t n); +/* Insert the data at index i of the vector and shift the other + items to the right. */ +int vector_insert(vector_p vec, size_t i, void* data, size_t n); +/* Get the index of the item in the vector that is equal to the data. + Equality is defined as having the same bytes in memory. */ +int vector_index(vector_p vec, void* data, size_t n); +/* Remove the item at index i of the vector and free its memory */ +void vector_remove(vector_p vec, size_t i); +/* Check to make sure there is still room in the vector and expand it if + necessary. This function is not meant to be called directly. */ +void check_length(vector_p vec); +/* Destroy the vector and free all the memory associated with it. */ +void destroy_vector(vector_p vec); +/* Swaps the pointers at indices i and j in the vector */ +void vector_swap(vector_p vec, int i, int j); + + +#endif