diff --git a/list.c b/list.c new file mode 100644 index 0000000..bee2554 --- /dev/null +++ b/list.c @@ -0,0 +1,257 @@ +#include "stdlib.h" +#include "stdio.h" + +#include "list.h" + +int l_push(list * l, void *data) +{ + l_node *n; + int ret; + + /* invalid input */ + if (!l || !data) { + return -1; + } + + n = l_init_node(data); + if (!n) { + /* something went wrong */ + return -2; + } + + ret = l_node_push(l, n); + + return ret; +} + +int l_node_push(list * l, l_node * n) +{ + l_node *end; + + /* invalid input */ + if (!l || !n) { + return -1; + } + + n->next = NULL; + + /* empty list */ + if (!l->head) { + l->head = n; + + return 0; + } + + for (end = l->head; end->next; end = end->next) ; + + if (end != n) { + end->next = n; + } + + return 0; +} + +void *l_pop(list * l) +{ + l_node *penultimate; + void *data; + + /* invalid input */ + if (!l) { + return NULL; + } + + /* empty list */ + if (!l->head) { + return NULL; + } + + /* len(l) == 1 */ + if (!l->head->next) { + data = l->head->data; + free(l->head); + l->head = NULL; + + return data; + } + + for (penultimate = l->head; + penultimate->next->next; penultimate = penultimate->next) ; + data = penultimate->next->data; + free(penultimate->next); + penultimate->next = NULL; + + return data; +} + +int l_insert(l_node * node, void *data) +{ + int ret; + l_node *to_be_inserted; + + /* invalid input */ + if (!node || !data) { + return -1; + } + + to_be_inserted = l_init_node(data); + if (!to_be_inserted) { + return -2; + } + + ret = l_node_insert(node, to_be_inserted); + + return ret; +} + +int l_node_insert(l_node * node, l_node * to_be_inserted) +{ + l_node *tmp; + + /* invalid input */ + if (!node || !to_be_inserted) { + return -1; + } + + tmp = node->next; + node->next = to_be_inserted; + to_be_inserted->next = tmp; + + return 0; +} + +void *l_remove(list * l, l_node * node) +{ + void *data; + l_node_remove(l, node); + data = node->data; + free(node); + + return data; +} + +l_node *l_node_remove(list * l, l_node * node) +{ + l_node *prev; + l_node *next; + + /* invalid input */ + if (!l || !node) { + return NULL; + } + + /* empty list */ + if (!l->head) { + return NULL; + } + + /* node is head */ + if (l->head == node) { + l->head = node->next; + node->next = NULL; + return node; + } + + /* find the predecessor of node */ + for (prev = l->head; + prev->next && prev->next != node; prev = prev->next) ; + + /* node not in list */ + if (prev->next != node) { + return node; + } + + next = node->next; + prev->next = next; + + return node; +} + +l_node *l_init_node(void *data) +{ + l_node *node; + + node = malloc(sizeof(l_node)); + if (!node) { + return NULL; + } + + node->data = data; + node->next = NULL; + + return node; +} + +int l_length(list * l) +{ + l_node *iter; + int count; + + if (!l || !l->head) { + return 0; + } + + count = 0; + iter = l->head; + while (iter) { + count++; + iter = iter->next; + } + + return count; +} + +int l_is_empty(list * l) +{ + return l->head == NULL; +} + +int l_move(list * from, list * to, l_node * node) +{ + + if (!from || !to || !node) { + return -1; + } + node = l_node_remove(from, node); + return l_node_push(to, node); +} + +list *l_init(void) +{ + list *l = malloc(sizeof(list)); + l->head = NULL; + + return l; +} + +void l_sort(list * l, int (*f) (void *, void *)) +{ + list *old_list = l_init(); + + if (!l || l_length(l) < 2) { + /* nothing to do */ + return; + } + + old_list->head = l->head; + l->head = NULL; + + while (!l_is_empty(old_list)) { + l_node *iter; + l_node *max; + + /* find max in old_list */ + max = old_list->head; + for (iter = old_list->head; iter; iter = iter->next) { + if (f(max->data, iter->data) < 0) { + max = iter; + } + } + + l_move(old_list, l, max); + } + + free(old_list); +} + +/* vim: set ts=8 sw=8 tw=0: */ diff --git a/list.h b/list.h new file mode 100644 index 0000000..800ee9c --- /dev/null +++ b/list.h @@ -0,0 +1,59 @@ +#ifndef _LIST_H +#define _LIST_H + +typedef struct _l_node { + struct _l_node *next; + void *data; +} l_node; + +typedef struct _list { + l_node *head; +} list; + +/* append to end of list */ +int l_push(list * l, void *data); + +/* same as append but with a l_node */ +int l_node_push(list * l, l_node * n); + +/* remove and return last element of list */ +void *l_pop(list * l); + +/* insert after node. */ +int l_insert(l_node * node, void *data); + +/* + * same as insert, but using a node_t + */ +int l_node_insert(l_node * node, l_node * to_be_inserted); + +/* + * remove l_node from list and return a pointer to its data + */ +void *l_remove(list * l, l_node * node); + +/* + * same as l_remove but returns the node instead of the data + */ +l_node *l_node_remove(list * l, l_node * node); + +/* + * initialize a node + */ +l_node *l_init_node(void *data); + +/* return the length of the list */ +int l_length(list * l); + +/* is list empty */ +int l_is_empty(list * l); + +/* move node from 'from' to 'to' */ +int l_move(list * from, list * to, l_node * node); + +void l_sort(list * l, int (*f) (void *, void *)); + +list *l_init(void); +#endif + +/* vim: set ts=8 sw=8 tw=0: */