Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linked list cleanup #26

Merged
merged 7 commits into from
Jan 4, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -41,6 +41,8 @@ examples: libraries
$(CC) $(STD) $(DISTDIR)/bitarray-lib.o $(EXAMPLEDIR)/bitarray_example.c $(CCFLAGS) $(COMPFLAGS) -o ./$(DISTDIR)/ex_bitarray
$(CC) $(STD) $(DISTDIR)/fileutils-lib.o $(EXAMPLEDIR)/fileutils_example.c $(CCFLAGS) $(COMPFLAGS) -o ./$(DISTDIR)/ex_fileutils
$(CC) $(STD) $(DISTDIR)/stringlib.o $(EXAMPLEDIR)/stringlib_example.c $(CCFLAGS) $(COMPFLAGS) -o ./$(DISTDIR)/ex_stringlib
$(CC) $(STD) $(DISTDIR)/llist-lib.o $(EXAMPLEDIR)/linkedlist_example.c $(CCFLAGS) $(COMPFLAGS) -o ./$(DISTDIR)/ex_linkedlist
$(CC) $(STD) $(DISTDIR)/dllist-lib.o $(EXAMPLEDIR)/doublylinkedlist_example.c $(CCFLAGS) $(COMPFLAGS) -o ./$(DISTDIR)/ex_doublylinkedlist

clean:
rm -rf ./$(DISTDIR)/*
84 changes: 84 additions & 0 deletions examples/doublylinkedlist_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*******************************************************************************
* Demonstrate some of the uses of the doubly linked list datastructure by
* adding people into a queue! We will make a person struct, to show it being
* used with a non-standard datatype.
*
* NOTE: One can make a queue (FIFO) using the data structure by making a
* macro for pop and push to ensure that one always pushes to the tail (-1)
* and pops from the front (0). A stack (LIFO) is best implemented using a
* doubly linked list pushes to the front and pops from the tail.
*
* Use -v to include more debugging information
*******************************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "../src/dllist.h"


typedef struct person {
int age;
char gender;
int height; /* feet */
int id; /* order of getting here; for testing */
} _person;


#define NUM_ELEMENTS 1000000

int main(int argc, char const *argv[]) {
bool verbose = false;

if (argc == 2 && strcmp(argv[1], "-v") == 0) {
verbose = true;
}
int i;
time_t t;
srand((unsigned) time(&t));

dllist_t l = dll_init();

for (i = 0; i < NUM_ELEMENTS; i++) {
_person* p = malloc(sizeof(_person));
p->age = rand() % 110 + 1;
p->gender = rand() % 2 == 0 ? 'm' : 'f';
p->height = rand() % 7 + 1;
p->id = i;
if (dll_insert(l, p, -1) == DLL_FAILURE) { /* we want to append to the end each time */
printf("Failed to allocate memory!\n");
}

assert(dll_num_elements(l) == (unsigned int)(i + 1));
}

int cnt = 0;
dll_node* n;
dll_reverse_traverse(l, n) { /* traverse for testing in reverse (from tail) */
_person* q = (_person*) n->data;
assert(q->id == NUM_ELEMENTS - ++cnt);
}
cnt = 0;
dll_traverse(l, n) { /* traverse for testing from the head node */
_person* q = (_person*) n->data;
assert(q->id == cnt++);
}

for (i = 1; i <= NUM_ELEMENTS; i++) {
_person* w = (_person*) dll_remove(l, 0);
assert((unsigned int)(NUM_ELEMENTS - i) == dll_num_elements(l));
if (verbose) {
printf("person: %d\tage: %d \tgender: %c\theight (feet): %d\n", w->id, w->age, w->gender, w->height);
}
free(w); /* it was pop'd but not yet free'd */
}

dll_free(l);

printf("Completed successfully!\n");
return 0;
}
80 changes: 80 additions & 0 deletions examples/linkedlist_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*******************************************************************************
* Demonstrate some of the uses of the linked list datastructure by
* adding points as a stack! We will make a point struct, to show it being
* used with a non-standard datatype.
*
* NOTE: One can make a stake using the data structure by making a macro for
* pop and push to ensure that one always pushes to the front (0) and pops
* from the front. A stack (LIFO) is best implemented using a singly linked
* list that always does all work from the head node.
*
* Use -v to include more debugging information
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include "../src/llist.h"

typedef struct point {
int x;
int y;
int z;
} _point;


#define NUM_ELEMENTS 9000


int main(int argc, char const *argv[]) {
bool verbose = false;

if (argc == 2 && strcmp(argv[1], "-v") == 0) {
verbose = true;
}

time_t t;
srand((unsigned) time(&t));

llist_t l = ll_init();

/* build out a list of points and add them to the stack*/
int i;
for (i = 0; i < NUM_ELEMENTS; i++) {
_point* p = malloc(sizeof(_point));
p->x = i;
p->y = rand() % 50;
p->z = i + 1;
ll_insert(l, p, 0); /* for a stack, everything must be up front */
}

/* traverse the list and make sure that each point's x is less than the previous */
int cnt = 0;
int prev = NUM_ELEMENTS + 1;
ll_node* n;
ll_traverse(l, n) { /* this is a macro to simplify n = n->next type loops */
_point* q = (_point*) n->data;
assert(prev > q->x);
prev = q->x;
}

/* for a stack, we need to "pop" or remove the first element each time */
for (i = 1; i <= NUM_ELEMENTS; i++) {
_point* w = (_point*) ll_remove(l, 0);
assert(NUM_ELEMENTS - i == w->x);
assert((unsigned int)(NUM_ELEMENTS - i) == ll_num_elements(l));
if (verbose) {
printf("point: %d\tx: %d\ty: %d\tz: %d\n", cnt++, w->x, w->y, w->z);
}
free(w); /* it was pop'd but not yet free'd */
}

assert(0 == ll_num_elements(l));

ll_free_alt(l, true);
printf("Completed successfully!\n");
return 0;
}
151 changes: 59 additions & 92 deletions src/dllist.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "dllist.h"



typedef struct __doubly_linked_list {
dll_node* head;
dll_node* tail;
@@ -16,7 +16,6 @@ dllist_t dll_init() {
l->head = NULL;
l->tail = NULL;
l->elms = 0;

return l;
}

@@ -50,31 +49,11 @@ dll_node* dll_last_node(dllist_t l) {
}

int dll_append(dllist_t l, void* data) {
dll_node* n = calloc(1, sizeof(dll_node));
if (n == NULL)
return DLL_FAILURE;

n->data = data;
n->next = NULL;
n->prev = NULL;

if (l->elms == 0) {
l->tail = n;
l->head = n;
++(l->elms);
return DLL_SUCCESS;
}

l->tail->next = n;
n->prev = l->tail;
l->tail = n;
++(l->elms);

return DLL_SUCCESS;
return dll_insert(l, data, -1);
}

int dll_insert(dllist_t l, void * data, int idx) {
if (idx < 0 && idx <= (-1 * (int)l->elms))
if (idx != -1 && idx < 0 && idx <= (-1 * (int)l->elms))
return DLL_FAILURE;

if (idx < 0)
@@ -89,38 +68,39 @@ int dll_insert(dllist_t l, void * data, int idx) {
n->next = NULL;
n->prev = NULL;

if (idx == 0) {
n->next = (l->head);
if (l->elms == 0) { /* first node to be added edge case */
l->head = n;
l->tail = n;
} else if (idx == 0) { /* first node */
n->next = l->head;
n->next->prev = n;
l->head = n;
++(l->elms);
return DLL_SUCCESS;
} else if (idx >= (int)l->elms) {
} else if (idx >= (int)l->elms) { /* last node */
l->tail->next = n;
n->prev = l->tail; /* we want the tail to point to the end */
l->tail = n;
++(l->elms);
return DLL_SUCCESS;
}

int i;
dll_node* t;
if (idx <= (int)l->elms / 2) {
t = dll_first_node(l);
for (i = 1; i < idx; i++)
t = t->next;
} else {
/* start from the tail and go backwards! */
int stop = l->elms - idx;
t = dll_last_node(l);
for (i = 0; i < stop; i++)
t = t->prev;
} else { /* mid node; determine which direction would be fastest to get to it */
int i;
dll_node* t;
if (idx <= (int)l->elms / 2) {
t = dll_first_node(l);
for (i = 1; i < idx; i++)
t = t->next;
} else {
/* start from the tail and go backwards! */
int stop = l->elms - idx;
t = dll_last_node(l);
for (i = 0; i < stop; i++)
t = t->prev;
}

n->next = t->next;
t->next = n;
n->next->prev = n;
n->prev = t;
}

n->next = t->next;
t->next = n;
n->next->prev = n;
n->prev = t;
++(l->elms);
return DLL_SUCCESS;
}

@@ -137,52 +117,39 @@ void* dll_remove(dllist_t l, int idx) {
if (idx < 0)
idx = l->elms + idx;

void* ret;
dll_node* n;
if (l->elms == 1) { /* this is the oddest edge case */
n = l->head;
ret = n->data;
l->head = NULL;
l->tail = NULL;
--l->elms;
free(n);
return ret;
} else if (idx == 0) { /* handle edge cases */
n = l->head;
ret = n->data;
void* data;
dll_node* ret;
if (l->elms == 1) { /* remove the final node */
ret = l->head;
l->head = l->tail = NULL;
} else if (idx == 0) { /* remove the first node */
ret = l->head;
l->head = l->head->next;
l->head->prev = NULL;
--l->elms;
free(n);
return ret;
} else if (idx >= (int)(l->elms - 1)) {
n = l->tail;
ret = n->data;
l->tail = n->prev;
n->prev->next = NULL;
--l->elms;
free(n);
return ret;
}

int i;
if (idx <= (int)l->elms / 2) {
n = dll_first_node(l);
for (i = 1; i < idx; i++)
n = n->next;
ret = l->tail;
l->tail = ret->prev;
ret->prev->next = NULL;
} else {
/* start from the tail and go backwards! */
int stop = l->elms - idx;
n = dll_last_node(l);
for (i = 0; i < stop; i++)
n = n->prev;
int i;
if (idx <= (int)l->elms / 2) {
ret = dll_first_node(l);
for (i = 1; i < idx; i++)
ret = ret->next;
} else {
/* start from the tail and go backwards! */
int stop = l->elms - idx;
ret = dll_last_node(l);
for (i = 0; i < stop; i++)
ret = ret->prev;
}

/* move the nodes before and after's pointers around */
ret->prev->next = ret->next;
ret->next->prev = ret->prev;
}

/* mode the nodes before and after's pointers around */
n->prev->next = n->next;
n->next->prev = n->prev;
ret = n->data;
--l->elms;
free(n);
return ret;
data = ret->data;
--(l->elms);
free(ret);
return data;
}
4 changes: 1 addition & 3 deletions src/dllist.h
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
*** Author: Tyler Barrus
*** email: barrust@gmail.com
***
*** Version: 0.1.0
*** Version: 0.1.1
*** Purpose: Generic doubly linked list implementation
***
*** License: MIT 2019
@@ -32,11 +32,9 @@
***
*******************************************************************************/


#include <stdbool.h>



typedef struct __doubly_linked_list dllist;
typedef struct __doubly_linked_list *dllist_t;

Loading