Friday, March 3, 2017

Simple implementation of a doubly linked list in C

Similarly to the previous blog post, here's a basic implementation of a doubly linked list in the C programming language.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <assert.h>

#define MAX_LEN   10
#define MAX_VAL   30

typedef struct node {
    int val;
    struct node *next;
    struct node *prev;
} node_t;

static int list_len = 0;

void
print_list(node_t *head, node_t *tail)
{
    node_t *node;
    int    cnt;

    node = head;
    cnt = 0;

    printf("printing fwd\n");
    while (node != NULL) {
        printf("[%d] %d\n", cnt++, node->val);
        node = node->next;
    }

    printf("printing bwd\n");
    node = tail;

    while (node != NULL) {
        printf("[%d] %d\n", --cnt, node->val);
        node = node->prev;
    }
}

void
init_list(node_t **head, node_t **tail)
{
    node_t *node, *last;
    int    i;

    do {
        list_len = rand() % MAX_LEN;
    } while (list_len == 0);

    printf("creating list with %d entries\n", list_len);

    for (i = 0; i < list_len; i++) {
        node = calloc(1, sizeof (node_t));
        node->val = rand() % MAX_VAL;
        node->next = *head;
        node->prev = NULL;
        *head = node;

        if (*tail == NULL) {
            *tail = node;
        }

        if (last != NULL) {
            last->prev = node;
        }

        last = node;
    }
}

void
reverse_list(node_t **head, node_t **tail)
{
    node_t *next, *prev, *new_head = NULL, *new_tail = NULL;

    printf("reversing\n");

    if (*head == NULL || *tail == NULL) {
        return;
    }
    if (*head == *tail) {
        printf("nothing to reverse\n");
        return;
    }

    next = *head;
    prev = *tail;

    while (next != NULL) {
        assert(prev != NULL);

        *head = next->next;
        *tail = prev->prev;

        next->next = new_head;
        prev->prev = new_tail;

        new_head = next;
        new_tail = prev;
        next = *head;
        prev = *tail;
    }

    assert(*head == NULL);
    assert(*tail == NULL);
    *head = new_head;
    *tail = new_tail;
}

void
remove_list(node_t **head, node_t **tail)
{
    node_t *prev, *tgt;
    int    item = 0, i, val;

    if (*head == NULL || *tail == NULL) {
        return;
    }

    item = rand() % list_len;

    tgt = *head;

    for (i = 0; i < item; i++) {
        assert(tgt != NULL);
        tgt = tgt->next;
    }

    printf("removing item %d :: %d\n", item, tgt->val);

    if (tgt->prev != NULL) {
        prev = tgt->prev;
        prev->next = tgt->next;
    }

    if (tgt->next != NULL) {
        tgt->next->prev = prev;
    }

    if (*head == tgt) {
        *head = tgt->next;
    }

    if (*tail == tgt) {
        *tail = prev;
    }

    free(tgt);
    list_len--;
}

int
main(int argc, char **argv)
{
    node_t *head, *tail;

    srand(time(NULL));

    init_list(&head, &tail);
    print_list(head, tail);

    reverse_list(&head, &tail);
    print_list(head, tail);

    remove_list(&head, &tail);
    print_list(head, tail);

    return (0);
}

No comments:

Post a Comment