generic linked list
This commit is contained in:
parent
98ad061b29
commit
305a791e21
257
list.c
Normal file
257
list.c
Normal file
@ -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: */
|
59
list.h
Normal file
59
list.h
Normal file
@ -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: */
|
Loading…
x
Reference in New Issue
Block a user