1 /* ################################################################### */
2 /* Copyright 2015, Pierre Gentile (p.gen.progs@gmail.com) */
4 /* This Source Code Form is subject to the terms of the Mozilla Public */
5 /* License, v. 2.0. If a copy of the MPL was not distributed with this */
6 /* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 /* ################################################################### */
9 /* ********************************************************************* */
10 /* Tiny linked list implementation. */
12 /* Each node contain a void pointer to some opaque data, these functions */
13 /* will not try to allocate or free this data pointer. */
15 /* Also accessors are not provided, the user has to directly manipulate */
16 /* the structure members (head, tail, len, data, prev, next). */
17 /* ********************************************************************* */
29 ll_partition(ll_node_t
*l
,
31 int (*comp
)(void const *, void const *),
32 void (*swap
)(void **, void **));
35 ll_quicksort(ll_node_t
*l
,
37 int (*comp
)(void const *, void const *),
38 void (*swap
)(void **, void **));
40 /* ========================== */
41 /* Creates a new linked list. */
42 /* ========================== */
46 ll_t
*ret
= xmalloc(sizeof(ll_t
));
52 /* ========================== */
53 /* Initializes a linked list. */
54 /* ========================== */
63 /* ====================================================== */
64 /* Allocates the space for a new node in the linked list. */
65 /* ====================================================== */
69 return xmalloc(sizeof(ll_node_t
));
72 /* ====================================================================== */
73 /* Appends a new node filled with its data at the end of the linked list. */
74 /* The user is responsible for the memory management of the data. */
76 /* Note: list is assumed to be initialized by ll_new(). */
77 /* ====================================================================== */
79 ll_append(ll_t
* const list
, void * const data
)
83 node
= ll_new_node(); /* ll_new_node cannot return NULL because it *
84 | uses xmalloc which does not return if there *
85 | is an allocation error. */
88 node
->next
= NULL
; /* This node will be the last. */
89 node
->prev
= list
->tail
; /* NULL if it is a new list. */
91 if (list
->tail
!= NULL
)
92 list
->tail
->next
= node
;
98 ++list
->len
; /* One more node in the list. */
101 /* ================================== */
102 /* Removes a node from a linked list. */
103 /* ================================== */
105 ll_delete(ll_t
* const list
, ll_node_t
*node
)
107 if (list
->head
== list
->tail
)
109 /* We delete the last remaining element from the list. */
110 /* """"""""""""""""""""""""""""""""""""""""""""""""""" */
111 if (list
->head
== NULL
)
114 list
->head
= list
->tail
= NULL
;
116 else if (node
->prev
== NULL
)
118 /* We delete the first element from the list. */
119 /* """""""""""""""""""""""""""""""""""""""""" */
120 list
->head
= node
->next
;
121 list
->head
->prev
= NULL
;
123 else if (node
->next
== NULL
)
125 /* We delete the last element from the list. */
126 /* """"""""""""""""""""""""""""""""""""""""" */
127 list
->tail
= node
->prev
;
128 list
->tail
->next
= NULL
;
132 /* We delete an element from the list. */
133 /* """"""""""""""""""""""""""""""""""" */
134 node
->next
->prev
= node
->prev
;
135 node
->prev
->next
= node
->next
;
140 --list
->len
; /* One less node in the list. */
145 /* ====================================================== */
146 /* Partition code for the quicksort function. */
147 /* Based on code found here: */
148 /* http://www.geeksforgeeks.org/quicksort-for-linked-list */
149 /* ====================================================== */
151 ll_partition(ll_node_t
*l
,
153 int (*comp
)(void const *, void const *),
154 void (*swap
)(void **, void **))
156 /* Considers last element as pivot, places the pivot element at its */
157 /* correct position in sorted array, and places all smaller (smaller than */
158 /* pivot) to left of pivot and all greater elements to right of pivot. */
159 /* """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */
161 /* Set pivot as h element. */
162 /* """"""""""""""""""""""" */
165 ll_node_t
*i
= l
->prev
;
168 for (j
= l
; j
!= h
; j
= j
->next
)
170 if (comp(j
->data
, x
) < 1)
172 i
= (i
== NULL
) ? l
: i
->next
;
174 swap(&(i
->data
), &(j
->data
));
178 i
= (i
== NULL
) ? l
: i
->next
;
179 swap(&(i
->data
), &(h
->data
));
184 /* ======================================================== */
185 /* A recursive implementation of quicksort for linked list. */
186 /* Based on code found here: */
187 /* http://www.geeksforgeeks.org/quicksort-for-linked-list */
188 /* ======================================================== */
190 ll_quicksort(ll_node_t
*l
,
192 int (*comp
)(void const *, void const *),
193 void (*swap
)(void **, void **))
195 if (h
!= NULL
&& l
!= h
&& l
!= h
->next
)
197 ll_node_t
*p
= ll_partition(l
, h
, comp
, swap
);
198 ll_quicksort(l
, p
->prev
, comp
, swap
);
199 ll_quicksort(p
->next
, h
, comp
, swap
);
203 /* ============================ */
204 /* A linked list sort function. */
205 /* ============================ */
208 int (*comp
)(void const *, void const *),
209 void (*swap
)(void **, void **))
211 /* Call the recursive ll_quicksort function. */
212 /* """"""""""""""""""""""""""""""""""""""""" */
213 ll_quicksort(list
->head
, list
->tail
, comp
, swap
);
216 /* ==========================================================================*/
217 /* Finds a node in the list containing data. Return the node pointer or NULL */
219 /* A comparison function must be provided to compare a and b (strcmp like). */
220 /* ==========================================================================*/
222 ll_find(ll_t
* const list
,
224 int (*cmpfunc
)(const void *, const void *))
228 if (NULL
== (node
= list
->head
))
233 if (0 == cmpfunc(node
->data
, data
))
235 } while (NULL
!= (node
= node
->next
));
240 /* =============================================== */
241 /* Free all the elements of a list (make it empty) */
242 /* NULL or a custom function may be used to free */
243 /* the sub components of the elements. */
244 /* =============================================== */
246 ll_free(ll_t
* const list
, void (*clean
)(void *))
250 ll_node_t
*node
= list
->head
;
254 /* Apply a custom cleaner if not NULL. */
255 /* """"""""""""""""""""""""""""""""""" */
259 ll_delete(list
, node
);
266 /* ==================================== */
267 /* Destroy a list and all its elements. */
268 /* ==================================== */
270 ll_destroy(ll_t
*list
, void (*clean
)(void *))
274 ll_free(list
, clean
);