libflint/docs/linkedlist.md

230 lines
6.2 KiB
Markdown
Raw Permalink Normal View History

# linkedlist
2022-03-31 00:02:36 +00:00
2023-10-25 16:21:59 +00:00
A dual sided linked list structure. Used as the foundation for many other modules in `libflint`
## Usage
Create the list. The user is responsible for memory management of the `List` struct.
```c
List *list = malloc(sizeof(List));
```
After the tree is created, init it. The second argument on `bintree_init()` is an optional memory freeing function pointer
with signature `void (*destroy)(void *data)`. Use `free()` from the stdlib if you are creating the data with `malloc()`.
If allocation of your data is more complex, you can pass your own memory deallocation function as long as it fits the
signature.
In this example, we are passing `NULL` because all memory will be stack allocated.
```c
ll_init(list, NULL);
int i = 1;
int j = 2;
int k = 4;
```
Next, insert data into the list. Data can be inserted from either side of a node.
```c
ll_ins_next(list, list->head, (void *) &i);
ll_ins_next(list, list->tail, (void *) &j);
ll_ins_next(list, list->tail, (void *) &k);
/* List is now 1 2 4 */
```
Lists can have a node removed by either targeting the node directly or removing a node pointed to by the head or tail of
another node. The user is responsible for the memory management of the data inside the node, which is why a `void*` must
be supplied to hold the data. Since in this example our memory is stack allocated, we don't need to worry about freeing
the `void*` but one must still be supplied for the function to work.
```c
/* List is 1 2 4 */
/* node is the 2nd node in the list with value 2 */
ListNode *node = list->head;
/* void pointer to the data inside of the node */
void *data;
ll_remove(list, node, &data);
/* List is now 1 4 */
printf("Removed: %d\n", *((int *) data));
/* Prints "2" */
```
Here is an alternative example using `ll_remove_next()` instead of `ll_remove()`
```c
/* node is the 2nd node in the list with value 2 */
ListNode *node = list->head;
void *data; /* void pointer to the data inside of the node */
ll_remove_next(list, node, &data);
/* List is now 1 2 */
printf("Removed: %d\n", *((int *) data));
/* Prints "4" */
```
To destroy the list, first call `ll_destroy()` to free the nodes in the list and optionally run the destroy function
against the data stored in the list. Since this example is stack allocated and we passed `NULL` when creating the
list, no destroy function is run against the memory in the nodes. The list itself must be deleted with `free()`
```c
ll_destroy(list);
free(list);
```
Complete example:
```c
List *list = malloc(sizeof(List));
ll_init(list, NULL);
int i = 1;
int j = 2;
int k = 4;
ll_ins_next(list, list->head, (void *) &i);
ll_ins_next(list, list->tail, (void *) &j);
ll_ins_next(list, list->tail, (void *) &k);
printf("List: ");
print_ll(list);
void *data;
ll_remove_next(list, list->head, &data);
printf("List: ");
print_ll(list);
printf("Removed: %d\n", *((int *) data));
ll_destroy(list);
free(list);
```
## Structs
### List
Double ended linked list struct
```c
typedef struct {
size_t size;
void (*destroy)(void *data);
int (*match)(const void *a, const void *b);
struct ListNode *head;
struct ListNode *tail;
} List;
```
Members:
- `size`: How many nodes are in the list
- `destroy`: Optional deallocation function for member data. Use `NULL` if data is stack allocated
- `match`: Comparison function between data inside two nodes. This is not used by `List` itself, but is used in structures built on top of `List`
- `head`: Pointer to the `ListNode` at the head of the list
- `tail`: Pointer to the `ListNode` at the tail of the list
### ListNode
Node of the list
```c
typedef struct ListNode {
void *data;
struct ListNode *next;
struct ListNode *prev;
} ListNode;
```
Members:
- `data`: void pointer to the member data in the node
- `next`: Pointer to the `ListNode` before this node in the list
- `prev`: Pointer to the `ListNode` after this node in the list
## Functions
### ll_init
2023-10-25 16:21:59 +00:00
Initialize the list. User is responsible for creating the initial `List` structure and freeing memory with `ll_destroy()`. `destroy` is a deallocation function for the members of `List`, pass `NULL` if the memory is stack-allocated
```c
void ll_init(List *list, void (*destroy)(void *data));
2023-10-25 16:21:59 +00:00
/* Usage */
List *list = malloc(sizeof(Stack));
// Pass NULL for stack-allocated memory
ll_init(list, NULL);
// Pass free or a custom freeing function for heap allocated memory
ll_init(list, free);
```
### ll_destroy
2023-10-25 16:21:59 +00:00
Destroys the nodes inside a list and calls the deallocation funciton on the data if one was provided. Does not destroy the list itself, that is left up to the user.
```c
void ll_destroy(List *list);
```
### ll_ins_next
Creates a new node containing `data` and inserts it after `node`.
```c
int ll_ins_next(List *list, ListNode *node, const void *data);
```
### ll_ins_prev
Creates a new node containing `data` and inserts it before `node`.
```c
int ll_ins_prev(List *list, ListNode *node, const void *data);
```
### ll_remove
Removes and deallocates the node pointed to by `node`. The user is responsible for managing the contained data's memory,
as such the `destroy` function is **not** run by `ll_remove()`
```c
int ll_remove(List *list, ListNode *node, void **data);
```
### ll_remove_next
Removes and deallocates the node pointed to by `node`'s `tail` pointer. The user is responsible for managing the contained data's memory,
as such the `destroy` function is **not** run by `ll_remove_next()`
```c
int ll_remove_next(List *list, ListNode *node, void **data);
```
### ll_remove_prev
Removes and deallocates the node pointed to by `node`'s `head` pointer. The user is responsible for managing the contained data's memory,
as such the `destroy` function is **not** run by `ll_remove_prev()`
```c
int ll_remove_prev(List *list, ListNode *node, void **data);
```
## Macros
### LL_ITER
A utility macro that helps with iterating over an entire list. A `ListNode` pointer named `node` is created as part of
this macro and can be used to access the current node in the iteration, so be careful your own variable naming if you
intend to use `LL_ITER`.
```c
#define LL_ITER(list) for(ListNode *node = (list)->head; node != NULL; node = node->next)
/* Example with list of strings */
for LL_ITER(list) {
printf("%s\n", (char *)(node->data));
}
```